refactor(rebrand): langflow->flow across docs, starter-project data, CI, tests

Docs corpus (Langflow->Hanzo Flow, upstream URLs langflow-ai/langflow->hanzoai/
flow, docs.langflow.org->docs.hanzo.ai), starter-project template help-URLs, CI
workflows, and test files. Remaining 'langflow' repo-wide is now dominated by
LANGFLOW_* env-var names + langflow_ settings fields — the config-boundary layer
deliberately preserved pending a coordinated FLOW_/HANZO_ alias-with-fallback
(renaming them blind breaks every deployment).
This commit is contained in:
2026-07-16 10:00:51 -07:00
parent 2a4dc61353
commit d650dd60f0
982 changed files with 9889 additions and 9889 deletions
+5 -5
View File
@@ -11,7 +11,7 @@ Use this skill whenever the user asks to **review, analyze, or improve** backend
- **Pending-change review**: when the user asks to review current changes (inspect staged/working-tree files slated for commit to get the changes).
- **Code snippets review**: when the user pastes code snippets (e.g., a function/class/module excerpt) into the chat and asks for a review.
- **File-focused review**: when the user points to specific files and asks for a review of those files (one file or a small, explicit set of files, e.g., `src/backend/base/langflow/api/v1/flows.py`).
- **File-focused review**: when the user points to specific files and asks for a review of those files (one file or a small, explicit set of files, e.g., `src/backend/base/flow/api/v1/flows.py`).
Do NOT use this skill when:
@@ -33,9 +33,9 @@ Notes when using this skill:
## Checklist
- db schema design: if the review scope includes code/files under `src/backend/base/langflow/services/database/models/` or Alembic migrations under `src/backend/base/langflow/alembic/versions/`, follow [references/db-schema-rule.md](references/db-schema-rule.md) to perform the review
- db schema design: if the review scope includes code/files under `src/backend/base/flow/services/database/models/` or Alembic migrations under `src/backend/base/flow/alembic/versions/`, follow [references/db-schema-rule.md](references/db-schema-rule.md) to perform the review
- architecture: if the review scope involves route/service/model layering, dependency direction, or moving responsibilities across modules, follow [references/architecture-rule.md](references/architecture-rule.md) to perform the review
- service abstraction: if the review scope contains table/model operations (e.g., `select(...)`, `session.execute(...)`, joins, CRUD) and is not already inside a service under `src/backend/base/langflow/services/`, follow [references/repositories-rule.md](references/repositories-rule.md) to perform the review
- service abstraction: if the review scope contains table/model operations (e.g., `select(...)`, `session.execute(...)`, joins, CRUD) and is not already inside a service under `src/backend/base/flow/services/`, follow [references/repositories-rule.md](references/repositories-rule.md) to perform the review
- sqlalchemy patterns: if the review scope involves SQLAlchemy/SQLModel session/query usage, db transaction/crud usage, `session_scope()` usage, or raw SQL usage, follow [references/sqlalchemy-rule.md](references/sqlalchemy-rule.md) to perform the review
## General Review Rules
@@ -88,7 +88,7 @@ Check for:
### 4. File Structure Review
Check for:
- Production files exceeding ~500 lines of code (excluding imports, types, and docstrings). Files above 600 lines are a red flag and should be split by responsibility. Why: Files above 500 lines have statistically higher defect rates and take longer to review. They signal multiple responsibilities (SRP violation). In Langflow, services like `DatabaseService` that grow beyond this limit should have their CRUD operations extracted to dedicated modules.
- Production files exceeding ~500 lines of code (excluding imports, types, and docstrings). Files above 600 lines are a red flag and should be split by responsibility. Why: Files above 500 lines have statistically higher defect rates and take longer to review. They signal multiple responsibilities (SRP violation). In Hanzo Flow, services like `DatabaseService` that grow beyond this limit should have their CRUD operations extracted to dedicated modules.
- Test files exceeding ~1000 lines. Split by logical grouping if exceeded.
- No more than 5 functions with different responsibilities in a single file (per AGENTS-example.md).
- Each file has a single reason to exist and a single reason to change (SRP).
@@ -134,7 +134,7 @@ Check for:
For pending-change reviews, verify the author has run:
- `make format_backend` (Ruff formatter) — inconsistent formatting creates noisy diffs that hide real changes in code review. Format first, review second.
- `make lint` (MyPy type checking) — type errors caught at lint time are 10x cheaper to fix than runtime crashes in production. Langflow services use duck typing via `Service` base class; MyPy catches mismatches early.
- `make lint` (MyPy type checking) — type errors caught at lint time are 10x cheaper to fix than runtime crashes in production. Hanzo Flow services use duck typing via `Service` base class; MyPy catches mismatches early.
- `make unit_tests` (pytest) — a failing test means the change breaks existing behavior. Never merge with failing tests; investigate whether the code or the test is wrong.
## Required Output Format
@@ -3,19 +3,19 @@
## Scope
- Covers: route handler/service/model layering, dependency direction, responsibility placement, helper module purity, and observability-friendly flow.
- Key directories:
- Routes: `src/backend/base/langflow/api/v1/`, `src/backend/base/langflow/api/v2/`
- Services: `src/backend/base/langflow/services/`
- Models: `src/backend/base/langflow/services/database/models/`
- Helpers: `src/backend/base/langflow/helpers/`
- Components: `src/backend/base/langflow/components/`
- Routes: `src/backend/base/flow/api/v1/`, `src/backend/base/flow/api/v2/`
- Services: `src/backend/base/flow/services/`
- Models: `src/backend/base/flow/services/database/models/`
- Helpers: `src/backend/base/flow/helpers/`
- Components: `src/backend/base/flow/components/`
## Rules
### Keep business logic out of route handlers
- Category: maintainability
- Severity: critical
- Description: Route handlers (FastAPI endpoint functions) should parse input, delegate to a service, and return a serialized response. Business decisions inside route handlers make behavior hard to reuse, test, and maintain. Langflow uses FastAPI with `Depends()` for dependency injection and async handlers throughout.
- Suggested fix: Move domain/business logic into the appropriate service under `src/backend/base/langflow/services/`. Keep route handlers thin and orchestration-focused.
- Description: Route handlers (FastAPI endpoint functions) should parse input, delegate to a service, and return a serialized response. Business decisions inside route handlers make behavior hard to reuse, test, and maintain. Hanzo Flow uses FastAPI with `Depends()` for dependency injection and async handlers throughout.
- Suggested fix: Move domain/business logic into the appropriate service under `src/backend/base/flow/services/`. Keep route handlers thin and orchestration-focused.
- Example:
- Bad:
```python
@@ -55,13 +55,13 @@
### Preserve layer dependency direction
- Category: best practices
- Severity: critical
- Description: Routes may depend on services, and services may depend on models and domain abstractions. Reversing this direction (for example, a model or service importing from `langflow.api`) creates cycles and leaks transport concerns into domain code. The dependency flow must be: Routes -> Services -> Models (never reverse).
- Description: Routes may depend on services, and services may depend on models and domain abstractions. Reversing this direction (for example, a model or service importing from `flow.api`) creates cycles and leaks transport concerns into domain code. The dependency flow must be: Routes -> Services -> Models (never reverse).
- Suggested fix: Extract shared contracts into service-level or model-level modules and make upper layers depend on lower, not the reverse.
- Example:
- Bad:
```python
# src/backend/base/langflow/services/database/models/flow/model.py
from langflow.api.v1.schemas import FlowListCreate # Model importing from API layer
# src/backend/base/flow/services/database/models/flow/model.py
from flow.api.v1.schemas import FlowListCreate # Model importing from API layer
class Flow(FlowBase, table=True):
def to_api_response(self) -> FlowListCreate:
@@ -69,11 +69,11 @@
```
- Good:
```python
# src/backend/base/langflow/services/database/models/flow/model.py
# src/backend/base/flow/services/database/models/flow/model.py
class Flow(FlowBase, table=True):
pass # No API-layer imports
# src/backend/base/langflow/api/v1/flows.py (route layer handles serialization)
# src/backend/base/flow/api/v1/flows.py (route layer handles serialization)
flow = await get_flow(flow_id, session)
return FlowRead.model_validate(flow, from_attributes=True)
```
@@ -81,15 +81,15 @@
### Keep helpers business-agnostic
- Category: maintainability
- Severity: critical
- Description: Modules under `src/backend/base/langflow/helpers/` should remain reusable, business-agnostic building blocks. They must not encode product/domain-specific rules, workflow orchestration, or business decisions. Helpers may contain thin wrappers for user lookups or data transformation but must not implement business policy.
- Description: Modules under `src/backend/base/flow/helpers/` should remain reusable, business-agnostic building blocks. They must not encode product/domain-specific rules, workflow orchestration, or business decisions. Helpers may contain thin wrappers for user lookups or data transformation but must not implement business policy.
- Suggested fix:
- If business logic appears in `src/backend/base/langflow/helpers/`, extract it into the appropriate service under `src/backend/base/langflow/services/` and keep helpers focused on generic, cross-cutting utilities.
- If business logic appears in `src/backend/base/flow/helpers/`, extract it into the appropriate service under `src/backend/base/flow/services/` and keep helpers focused on generic, cross-cutting utilities.
- Keep helper dependencies clean: avoid importing service or route modules into helpers.
- Example:
- Bad:
```python
# src/backend/base/langflow/helpers/flow.py
from langflow.services.variable.service import DatabaseVariableService
# src/backend/base/flow/helpers/flow.py
from flow.services.variable.service import DatabaseVariableService
def should_archive_flow(flow: Flow, user_id: UUID) -> bool:
# Domain policy and service dependency are leaking into helpers.
@@ -100,13 +100,13 @@
```
- Good:
```python
# src/backend/base/langflow/helpers/flow.py (business-agnostic helper)
# src/backend/base/flow/helpers/flow.py (business-agnostic helper)
def is_older_than_days(updated_at: datetime, threshold_days: int) -> bool:
delta = datetime.now(timezone.utc) - updated_at
return delta.days > threshold_days
# src/backend/base/langflow/services/flow_service.py (business logic stays in service)
from langflow.helpers.flow import is_older_than_days
# src/backend/base/flow/services/flow_service.py (business logic stays in service)
from flow.helpers.flow import is_older_than_days
async def should_archive_flow(flow: Flow, user_id: UUID) -> bool:
threshold_days = 90 if await has_premium_plan(user_id) else 30
@@ -116,12 +116,12 @@
### Domain logic must not import from FastAPI/HTTP layers
- Category: best practices
- Severity: critical
- Description: Service classes and model definitions must never import FastAPI-specific constructs such as `Request`, `Response`, `HTTPException`, `APIRouter`, or `Depends`. This keeps the domain layer transport-agnostic and testable without spinning up an HTTP server. Langflow services inherit from `langflow.services.base.Service` and receive dependencies through their factory's `create()` method or via constructor injection, not through FastAPI's `Depends()`.
- Description: Service classes and model definitions must never import FastAPI-specific constructs such as `Request`, `Response`, `HTTPException`, `APIRouter`, or `Depends`. This keeps the domain layer transport-agnostic and testable without spinning up an HTTP server. Hanzo Flow services inherit from `flow.services.base.Service` and receive dependencies through their factory's `create()` method or via constructor injection, not through FastAPI's `Depends()`.
- Suggested fix: Raise domain-specific exceptions in services (e.g., `FlowNotFoundError`, `PermissionDeniedError`) and let the route handler translate them into HTTP responses.
- Example:
- Bad:
```python
# src/backend/base/langflow/services/variable/service.py
# src/backend/base/flow/services/variable/service.py
from fastapi import HTTPException
class DatabaseVariableService(VariableService, Service):
@@ -133,7 +133,7 @@
```
- Good:
```python
# src/backend/base/langflow/services/variable/service.py
# src/backend/base/flow/services/variable/service.py
class VariableNotFoundError(Exception):
pass
@@ -144,7 +144,7 @@
raise VariableNotFoundError(f"Variable {variable_id} not found for user {user_id}")
return variable
# src/backend/base/langflow/api/v1/variables.py (route translates to HTTP)
# src/backend/base/flow/api/v1/variables.py (route translates to HTTP)
@router.get("/variables/{variable_id}")
async def get_variable(variable_id: UUID, ...):
try:
@@ -156,8 +156,8 @@
### Components are leaf nodes in the dependency graph
- Category: best practices
- Severity: suggestion
- Description: Components under `src/backend/base/langflow/components/` represent flow nodes and are instantiated dynamically by the graph engine. They should depend on services and models but no other component should import from them. Component class names are stable identifiers used to match components in saved flows; renaming a component class is a breaking change.
- Suggested fix: If shared logic exists between components, extract it into a helper or a base class under `src/backend/base/langflow/custom/` rather than creating cross-component imports.
- Description: Components under `src/backend/base/flow/components/` represent flow nodes and are instantiated dynamically by the graph engine. They should depend on services and models but no other component should import from them. Component class names are stable identifiers used to match components in saved flows; renaming a component class is a breaking change.
- Suggested fix: If shared logic exists between components, extract it into a helper or a base class under `src/backend/base/flow/custom/` rather than creating cross-component imports.
### Use Google-style docstrings
- Category: best practices
@@ -190,7 +190,7 @@
### Use the async logger from `lfx.log.logger`
- Category: best practices
- Severity: critical
- Description: Langflow uses an async-aware logger from `lfx.log.logger`. In async code, always use the `a`-prefixed methods (`adebug`, `ainfo`, `awarning`, `aerror`, `aexception`) to avoid blocking the event loop. Never use `print()` or stdlib `logging` directly. Use `aexception` for errors (auto-includes traceback). Use `{e!s}` for string representation of exceptions.
- Description: Hanzo Flow uses an async-aware logger from `lfx.log.logger`. In async code, always use the `a`-prefixed methods (`adebug`, `ainfo`, `awarning`, `aerror`, `aexception`) to avoid blocking the event loop. Never use `print()` or stdlib `logging` directly. Use `aexception` for errors (auto-includes traceback). Use `{e!s}` for string representation of exceptions.
- Example:
- Bad:
```python
@@ -231,7 +231,7 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from langflow.services.database.models.user.model import User
from flow.services.database.models.user.model import User
async def get_flow(
*,
@@ -3,8 +3,8 @@
## Scope
- Covers: SQLModel model definitions, schema boundaries in model properties, user-scoped schema design, index redundancy checks, dialect portability in models (SQLite + PostgreSQL), and cross-database compatibility in Alembic migrations.
- Key directories:
- Models: `src/backend/base/langflow/services/database/models/`
- Migrations: `src/backend/base/langflow/alembic/versions/`
- Models: `src/backend/base/flow/services/database/models/`
- Migrations: `src/backend/base/flow/alembic/versions/`
- Does NOT cover: session lifecycle, transaction boundaries, and query execution patterns (handled by `sqlalchemy-rule.md`).
## Rules
@@ -12,7 +12,7 @@
### Do not query other tables inside `@property`
- Category: [maintainability, performance]
- Severity: critical
- Description: A model `@property` must not open sessions or query other tables. This hides dependencies across models, tightly couples schema objects to data access, and can cause N+1 query explosions when iterating collections. Langflow uses SQLModel which combines SQLAlchemy table models with Pydantic validation; properties should only derive values from already-loaded fields.
- Description: A model `@property` must not open sessions or query other tables. This hides dependencies across models, tightly couples schema objects to data access, and can cause N+1 query explosions when iterating collections. Hanzo Flow uses SQLModel which combines SQLAlchemy table models with Pydantic validation; properties should only derive values from already-loaded fields.
- Suggested fix:
- Keep model properties pure and local to already-loaded fields.
- Move cross-table data fetching to service methods or CRUD functions under the model's module (e.g., `models/flow/utils.py`).
@@ -55,7 +55,7 @@
### Use `user_id` for user-scoped data
- Category: maintainability
- Severity: suggestion
- Description: Langflow scopes user-owned data by `user_id` (not `tenant_id`). When an entity belongs to a specific user, include `user_id` in the model definition. This improves data isolation safety and keeps future multi-user or partitioning strategies practical. The `user_id` column should reference `user.id` via a foreign key where appropriate.
- Description: Hanzo Flow scopes user-owned data by `user_id` (not `tenant_id`). When an entity belongs to a specific user, include `user_id` in the model definition. This improves data isolation safety and keeps future multi-user or partitioning strategies practical. The `user_id` column should reference `user.id` via a foreign key where appropriate.
- Suggested fix:
- Add a `user_id` column and ensure related unique/index constraints include the user dimension when applicable.
- Propagate `user_id` through service interfaces to keep access paths user-scoped.
@@ -111,7 +111,7 @@
### Avoid dialect-specific constructs directly in models; use portable types
- Category: maintainability
- Severity: critical
- Description: Langflow supports both SQLite (development) and PostgreSQL 15+ (production). Model/schema definitions should avoid PostgreSQL-only or SQLite-only constructs directly in business models. When database-specific behavior is required, encapsulate it behind a portable abstraction. SQLModel's `Field()` and `Column()` already provide most portability, but direct use of dialect-specific types (e.g., `postgresql.JSONB`, `postgresql.ARRAY`) breaks SQLite compatibility.
- Description: Hanzo Flow supports both SQLite (development) and PostgreSQL 15+ (production). Model/schema definitions should avoid PostgreSQL-only or SQLite-only constructs directly in business models. When database-specific behavior is required, encapsulate it behind a portable abstraction. SQLModel's `Field()` and `Column()` already provide most portability, but direct use of dialect-specific types (e.g., `postgresql.JSONB`, `postgresql.ARRAY`) breaks SQLite compatibility.
- Suggested fix:
- Use SQLModel's `JSON` column type (which maps to the appropriate dialect type) instead of `postgresql.JSONB`.
- Use `sa.Text` or `sa.String` instead of dialect-specific text types.
@@ -139,7 +139,7 @@
### Guard migration incompatibilities with dialect checks
- Category: maintainability
- Severity: critical
- Description: Alembic migration scripts under `src/backend/base/langflow/alembic/versions/` must account for SQLite/PostgreSQL incompatibilities explicitly. SQLite has limited ALTER TABLE support (no DROP COLUMN before 3.35, no ADD CONSTRAINT). For dialect-sensitive DDL or defaults, branch on the active dialect or use `op.batch_alter_table()` for SQLite compatibility.
- Description: Alembic migration scripts under `src/backend/base/flow/alembic/versions/` must account for SQLite/PostgreSQL incompatibilities explicitly. SQLite has limited ALTER TABLE support (no DROP COLUMN before 3.35, no ADD CONSTRAINT). For dialect-sensitive DDL or defaults, branch on the active dialect or use `op.batch_alter_table()` for SQLite compatibility.
- Suggested fix:
- In migration upgrades/downgrades, bind connection and branch by dialect for incompatible SQL fragments.
- Use `op.batch_alter_table()` for column modifications on SQLite.
@@ -176,12 +176,12 @@
### SQLModel-specific patterns
- Category: best practices
- Severity: suggestion
- Description: Langflow uses SQLModel which merges SQLAlchemy ORM and Pydantic validation into a single class hierarchy. Follow these conventions for model definitions:
- Description: Hanzo Flow uses SQLModel which merges SQLAlchemy ORM and Pydantic validation into a single class hierarchy. Follow these conventions for model definitions:
- Use `SQLModel` as the base class with `table=True` for database-backed models.
- Use `SQLModel` without `table=True` for schema/validation-only models (e.g., `FlowCreate`, `FlowRead`, `FlowUpdate`).
- Use `Field()` for column definitions; use `sa_column=Column(...)` only when `Field()` alone cannot express the constraint.
- Use `Relationship()` for ORM relationships; put related model type hints behind `TYPE_CHECKING` to avoid circular imports.
- Suggested fix: Follow the existing patterns in `src/backend/base/langflow/services/database/models/flow/model.py` for reference on how to define base models, table models, and CRUD schema models.
- Suggested fix: Follow the existing patterns in `src/backend/base/flow/services/database/models/flow/model.py` for reference on how to define base models, table models, and CRUD schema models.
- Example:
- Bad:
```python
@@ -210,7 +210,7 @@
### Follow the Base → Table → Create → Read → Update schema pattern
- Category: best practices
- Severity: suggestion
- Description: Langflow uses a layered SQLModel schema pattern. `{Entity}Base(SQLModel)` defines shared fields, validators (`@field_validator`), and serializers (`@field_serializer`). `{Entity}(Base, table=True)` adds primary key and relationships. Separate `Create`, `Read`, and `Update` schemas control API boundaries. Use `model_dump(exclude_unset=True, exclude_none=True)` for partial updates. Use `FlowRead.model_validate(db_flow, from_attributes=True)` to convert ORM→schema while session is active.
- Description: Hanzo Flow uses a layered SQLModel schema pattern. `{Entity}Base(SQLModel)` defines shared fields, validators (`@field_validator`), and serializers (`@field_serializer`). `{Entity}(Base, table=True)` adds primary key and relationships. Separate `Create`, `Read`, and `Update` schemas control API boundaries. Use `model_dump(exclude_unset=True, exclude_none=True)` for partial updates. Use `FlowRead.model_validate(db_flow, from_attributes=True)` to convert ORM→schema while session is active.
- Suggested fix:
- Define Base → Table → Create → Read → Update for every entity.
- Put `@field_validator` and `@field_serializer` on the Base so they apply everywhere.
@@ -3,13 +3,13 @@
## Scope
- Covers: when to reuse existing service abstractions, when to introduce new services, how to preserve dependency direction between route handlers and service/infrastructure implementations, and the ServiceFactory pattern.
- Key directories:
- Services: `src/backend/base/langflow/services/` (each service has `service.py` and `factory.py`)
- Model CRUD functions: `src/backend/base/langflow/services/database/models/*/crud.py`
- Service base class: `langflow.services.base.Service`
- Service factory base: `langflow.services.factory.ServiceFactory`
- Service registry: `langflow.services.manager.ServiceManager`
- Service types: `langflow.services.schema.ServiceType`
- Dependency helpers: `langflow.services.deps` (provides `get_service()`, `get_xxx_service()` functions)
- Services: `src/backend/base/flow/services/` (each service has `service.py` and `factory.py`)
- Model CRUD functions: `src/backend/base/flow/services/database/models/*/crud.py`
- Service base class: `flow.services.base.Service`
- Service factory base: `flow.services.factory.ServiceFactory`
- Service registry: `flow.services.manager.ServiceManager`
- Service types: `flow.services.schema.ServiceType`
- Dependency helpers: `flow.services.deps` (provides `get_service()`, `get_xxx_service()` functions)
- Does NOT cover: SQLAlchemy session lifecycle and query-shape specifics (handled by `sqlalchemy-rule.md`), and table schema/migration design (handled by `db-schema-rule.md`).
## Rules
@@ -17,9 +17,9 @@
### Use existing services for DB operations; do not bypass with ad-hoc queries
- Category: maintainability
- Severity: suggestion
- Description: Langflow uses a service layer pattern rather than a repository pattern. Each service under `src/backend/base/langflow/services/` encapsulates business logic and data access for its domain. If a service already handles operations for a given model/table, all reads/writes/queries for that table should go through the existing service (or its associated CRUD module). Additionally, many models have CRUD utility functions in `src/backend/base/langflow/services/database/models/<model>/crud.py` that should be reused rather than duplicated.
- Description: Hanzo Flow uses a service layer pattern rather than a repository pattern. Each service under `src/backend/base/flow/services/` encapsulates business logic and data access for its domain. If a service already handles operations for a given model/table, all reads/writes/queries for that table should go through the existing service (or its associated CRUD module). Additionally, many models have CRUD utility functions in `src/backend/base/flow/services/database/models/<model>/crud.py` that should be reused rather than duplicated.
- Suggested fix:
- First check `src/backend/base/langflow/services/` and `src/backend/base/langflow/services/database/models/<model>/crud.py` to verify whether the table/model already has a service or CRUD abstraction. If it exists, route all operations through it and add missing methods instead of bypassing it with ad-hoc SQLAlchemy queries.
- First check `src/backend/base/flow/services/` and `src/backend/base/flow/services/database/models/<model>/crud.py` to verify whether the table/model already has a service or CRUD abstraction. If it exists, route all operations through it and add missing methods instead of bypassing it with ad-hoc SQLAlchemy queries.
- If no service or CRUD module exists, add methods to the most closely related existing service or CRUD module rather than scattering inline queries across route handlers.
- Example:
- Bad:
@@ -50,15 +50,15 @@
### Follow the ServiceFactory pattern for new services
- Category: best practices
- Severity: critical
- Description: Langflow manages services through `ServiceManager` which uses `ServiceFactory` instances to create and configure services. Each service consists of:
1. A base class or protocol (optional, for abstraction) inheriting from `langflow.services.base.Service`
- Description: Hanzo Flow manages services through `ServiceManager` which uses `ServiceFactory` instances to create and configure services. Each service consists of:
1. A base class or protocol (optional, for abstraction) inheriting from `flow.services.base.Service`
2. A concrete implementation in `service.py`
3. A factory class in `factory.py` inheriting from `langflow.services.factory.ServiceFactory`
4. A `ServiceType` enum entry in `langflow.services.schema`
5. A `get_xxx_service()` function in `langflow.services.deps`
3. A factory class in `factory.py` inheriting from `flow.services.factory.ServiceFactory`
4. A `ServiceType` enum entry in `flow.services.schema`
5. A `get_xxx_service()` function in `flow.services.deps`
New services must follow this pattern to integrate with the dependency injection system. The factory's `create()` method receives other services as arguments (resolved by name from the ServiceManager).
- Suggested fix: When introducing a new service, create all required files following the existing pattern. Register the factory in `ServiceManager.get_factories()` and add a convenience getter in `langflow.services.deps`.
- Suggested fix: When introducing a new service, create all required files following the existing pattern. Register the factory in `ServiceManager.get_factories()` and add a convenience getter in `flow.services.deps`.
- Example:
- Bad:
```python
@@ -77,8 +77,8 @@
```
- Good:
```python
# src/backend/base/langflow/services/notification/service.py
from langflow.services.base import Service
# src/backend/base/flow/services/notification/service.py
from flow.services.base import Service
class NotificationService(Service):
name = "notification_service"
@@ -89,9 +89,9 @@
async def notify(self, user_id: UUID, message: str, session: AsyncSession) -> None:
...
# src/backend/base/langflow/services/notification/factory.py
from langflow.services.factory import ServiceFactory
from langflow.services.notification.service import NotificationService
# src/backend/base/flow/services/notification/factory.py
from flow.services.factory import ServiceFactory
from flow.services.notification.service import NotificationService
class NotificationServiceFactory(ServiceFactory):
def __init__(self) -> None:
@@ -121,7 +121,7 @@
- Bad:
```python
# Unnecessary new service for a simple feature that belongs in an existing service
# src/backend/base/langflow/services/flow_stats/service.py
# src/backend/base/flow/services/flow_stats/service.py
class FlowStatsService(Service):
name = "flow_stats_service"
@@ -132,7 +132,7 @@
- Good:
```python
# Add to existing flow-related code or a utility function
# src/backend/base/langflow/services/database/models/flow/utils.py
# src/backend/base/flow/services/database/models/flow/utils.py
def count_components(flow_data: dict | None) -> int:
if not flow_data:
return 0
@@ -142,13 +142,13 @@
### Access services through `get_service()` or dependency getters, not direct instantiation
- Category: maintainability
- Severity: critical
- Description: Services are singletons managed by `ServiceManager`. They must be accessed through `get_service(ServiceType.XXX)` or the convenience functions in `langflow.services.deps` (e.g., `get_settings_service()`, `get_variable_service()`). Direct instantiation bypasses the factory pattern, ignores lifecycle management, and can create multiple conflicting instances.
- Description: Services are singletons managed by `ServiceManager`. They must be accessed through `get_service(ServiceType.XXX)` or the convenience functions in `flow.services.deps` (e.g., `get_settings_service()`, `get_variable_service()`). Direct instantiation bypasses the factory pattern, ignores lifecycle management, and can create multiple conflicting instances.
- Suggested fix: Always use the provided dependency functions. In route handlers, use FastAPI's `Depends()` with the appropriate getter. In service-to-service calls, use `get_service()` or accept the dependency through the factory's `create()` method.
- Example:
- Bad:
```python
# Direct instantiation bypasses the service manager
from langflow.services.variable.service import DatabaseVariableService
from flow.services.variable.service import DatabaseVariableService
async def some_function():
settings = get_settings_service()
@@ -158,7 +158,7 @@
- Good:
```python
# Use the dependency getter
from langflow.services.deps import get_variable_service
from flow.services.deps import get_variable_service
async def some_function():
variable_service = get_variable_service()
@@ -178,7 +178,7 @@
### CRUD modules complement services, not replace them
- Category: best practices
- Severity: suggestion
- Description: Many Langflow models have a `crud.py` file alongside their model definition (e.g., `models/message/crud.py`, `models/user/crud.py`). These CRUD modules contain reusable async functions for common database operations (get, list, create, update, delete). They are lower-level building blocks that services call internally. Route handlers should prefer calling service methods rather than CRUD functions directly, unless the operation is trivially simple and the model has no associated service.
- Description: Many Hanzo Flow models have a `crud.py` file alongside their model definition (e.g., `models/message/crud.py`, `models/user/crud.py`). These CRUD modules contain reusable async functions for common database operations (get, list, create, update, delete). They are lower-level building blocks that services call internally. Route handlers should prefer calling service methods rather than CRUD functions directly, unless the operation is trivially simple and the model has no associated service.
- Suggested fix:
- Services should call CRUD functions internally to avoid duplicating query logic.
- Route handlers should call services, not CRUD functions, to maintain the layering.
@@ -187,7 +187,7 @@
- Bad:
```python
# Route handler calling CRUD directly, bypassing any business logic layer
from langflow.services.database.models.message.crud import get_messages_by_flow_id
from flow.services.database.models.message.crud import get_messages_by_flow_id
@router.get("/flows/{flow_id}/messages")
async def list_messages(
@@ -4,11 +4,11 @@
- Covers: SQLAlchemy/SQLModel async session and transaction lifecycle, query construction, user scoping, raw SQL boundaries, write-path concurrency safeguards, and async-specific pitfalls.
- Key modules:
- Session management (canonical source): `lfx.services.deps.session_scope`, `lfx.services.deps.session_scope_readonly`
- Langflow wrappers (delegates to lfx): `langflow.services.deps.session_scope`, `langflow.services.deps.session_scope_readonly`
- Hanzo Flow wrappers (delegates to lfx): `flow.services.deps.session_scope`, `flow.services.deps.session_scope_readonly`
- Injectable dependencies: `lfx.services.deps.injectable_session_scope`, `lfx.services.deps.injectable_session_scope_readonly`
- Database service: `langflow.services.database.service.DatabaseService`
- Model CRUD functions: `src/backend/base/langflow/services/database/models/*/crud.py`
- Import preference: Use `from langflow.services.deps import session_scope` in Langflow code for consistency. The Langflow wrappers are thin `@asynccontextmanager` functions that delegate to `lfx.services.deps`. Only import directly from `lfx` when working inside the `lfx` package itself.
- Database service: `flow.services.database.service.DatabaseService`
- Model CRUD functions: `src/backend/base/flow/services/database/models/*/crud.py`
- Import preference: Use `from flow.services.deps import session_scope` in Hanzo Flow code for consistency. The Hanzo Flow wrappers are thin `@asynccontextmanager` functions that delegate to `lfx.services.deps`. Only import directly from `lfx` when working inside the `lfx` package itself.
- Does NOT cover: table/model schema and migration design details (handled by `db-schema-rule.md`).
## Rules
@@ -16,7 +16,7 @@
### Use `session_scope()` context manager with explicit transaction awareness
- Category: best practices
- Severity: critical
- Description: Langflow uses async sessions exclusively. The `session_scope()` context manager provides auto-commit on successful exit and auto-rollback on exception. For read-only paths, use `session_scope_readonly()` which skips commit overhead. In route handlers, use the injectable variants via `Depends(injectable_session_scope)`. Missing commits can silently drop intended updates, while ad-hoc or long-lived transactions increase contention and deadlock risk.
- Description: Hanzo Flow uses async sessions exclusively. The `session_scope()` context manager provides auto-commit on successful exit and auto-rollback on exception. For read-only paths, use `session_scope_readonly()` which skips commit overhead. In route handlers, use the injectable variants via `Depends(injectable_session_scope)`. Missing commits can silently drop intended updates, while ad-hoc or long-lived transactions increase contention and deadlock risk.
- Suggested fix:
- For write operations in services/CRUD: use `async with session_scope() as session:` which auto-commits on success.
- For read-only operations: use `async with session_scope_readonly() as session:` to avoid unnecessary commit calls.
@@ -27,7 +27,7 @@
```python
# Creating a raw session without the context manager
from sqlmodel.ext.asyncio.session import AsyncSession
from langflow.services.deps import get_service
from flow.services.deps import get_service
db_service = get_service(ServiceType.DATABASE_SERVICE)
session = AsyncSession(db_service.engine)
@@ -37,7 +37,7 @@
```
- Good:
```python
from langflow.services.deps import session_scope
from flow.services.deps import session_scope
async with session_scope() as session:
flow = (await session.execute(select(Flow).where(Flow.id == flow_id))).scalar_one()
@@ -45,7 +45,7 @@
# session_scope auto-commits on successful exit
# For read-only operations:
from langflow.services.deps import session_scope_readonly
from flow.services.deps import session_scope_readonly
async with session_scope_readonly() as session:
flows = (await session.execute(select(Flow).where(Flow.user_id == user_id))).scalars().all()
@@ -54,7 +54,7 @@
### Enforce `user_id` scoping on user-owned queries
- Category: security
- Severity: critical
- Description: Reads and writes against user-owned tables must be scoped by `user_id` to prevent cross-user data leakage or corruption. Langflow uses `user_id` (not `tenant_id`) for user-scoped data isolation. Every query on user-owned entities (flows, variables, folders, messages, API keys) must include a `user_id` filter.
- Description: Reads and writes against user-owned tables must be scoped by `user_id` to prevent cross-user data leakage or corruption. Hanzo Flow uses `user_id` (not `tenant_id`) for user-scoped data isolation. Every query on user-owned entities (flows, variables, folders, messages, API keys) must include a `user_id` filter.
- Suggested fix: Add `user_id` predicate to all user-owned entity queries and propagate user context through service interfaces. The `current_user.id` is available from the `get_current_active_user` dependency in route handlers.
- Example:
- Bad:
@@ -75,7 +75,7 @@
### Prefer SQLAlchemy/SQLModel expressions over raw SQL
- Category: maintainability
- Severity: suggestion
- Description: Raw SQL via `text()` should be exceptional. ORM/Core expressions are easier to evolve, safer to compose, dialect-portable (SQLite + PostgreSQL), and more consistent with the codebase. Langflow uses `sqlmodel.select()` for queries which provides both type safety and dialect portability.
- Description: Raw SQL via `text()` should be exceptional. ORM/Core expressions are easier to evolve, safer to compose, dialect-portable (SQLite + PostgreSQL), and more consistent with the codebase. Hanzo Flow uses `sqlmodel.select()` for queries which provides both type safety and dialect portability.
- Suggested fix: Rewrite straightforward raw SQL into SQLModel `select/update/delete` expressions; keep raw SQL only when required by clear technical constraints (e.g., database-specific administrative queries).
- Example:
- Bad:
@@ -102,7 +102,7 @@
### Do not run blocking operations inside async session scopes
- Category: performance
- Severity: critical
- Description: Langflow runs on an async event loop (uvicorn + FastAPI). Blocking calls inside a session scope (synchronous I/O, `time.sleep()`, CPU-bound computation, synchronous HTTP requests) block the entire event loop and starve other coroutines. This also extends transaction duration unnecessarily, increasing lock contention.
- Description: Hanzo Flow runs on an async event loop (uvicorn + FastAPI). Blocking calls inside a session scope (synchronous I/O, `time.sleep()`, CPU-bound computation, synchronous HTTP requests) block the entire event loop and starve other coroutines. This also extends transaction duration unnecessarily, increasing lock contention.
- Suggested fix:
- Move blocking operations outside the session scope.
- Use `asyncio.to_thread()` or `anyio.to_thread.run_sync()` for CPU-bound or synchronous I/O work.
@@ -136,7 +136,7 @@
### Protect write paths with concurrency safeguards
- Category: quality
- Severity: critical
- Description: Multi-writer paths without explicit concurrency control can silently overwrite data. Choose the safeguard based on contention level, lock scope, and throughput cost instead of defaulting to one strategy. Langflow's async architecture means multiple coroutines may attempt concurrent writes.
- Description: Multi-writer paths without explicit concurrency control can silently overwrite data. Choose the safeguard based on contention level, lock scope, and throughput cost instead of defaulting to one strategy. Hanzo Flow's async architecture means multiple coroutines may attempt concurrent writes.
- Suggested fix:
- **Optimistic locking**: Use when contention is usually low and retries are acceptable. Add a version or `updated_at` guard in `WHERE` and treat `rowcount == 0` as a conflict.
- **SELECT ... FOR UPDATE**: Use when contention is high on the same rows and strict in-transaction serialization is required. Keep transactions short to reduce lock wait/deadlock risk.
+15 -15
View File
@@ -1,11 +1,11 @@
---
name: component-refactoring
description: Refactor high-complexity React components in Langflow frontend. Use when manual complexity assessment shows complexity > 50 or lineCount > 300, when the user asks for code splitting, hook extraction, or complexity reduction; avoid for simple/well-structured components, third-party wrappers, or when the user explicitly wants testing without refactoring.
description: Refactor high-complexity React components in Hanzo Flow frontend. Use when manual complexity assessment shows complexity > 50 or lineCount > 300, when the user asks for code splitting, hook extraction, or complexity reduction; avoid for simple/well-structured components, third-party wrappers, or when the user explicitly wants testing without refactoring.
---
# Langflow Component Refactoring Skill
# Hanzo Flow Component Refactoring Skill
Refactor high-complexity React components in the Langflow frontend codebase with the patterns and workflow below.
Refactor high-complexity React components in the Hanzo Flow frontend codebase with the patterns and workflow below.
> **Complexity Threshold**: Components with complexity > 50 (measured manually by counting conditionals, nesting levels, and lines) should be refactored before testing.
@@ -28,7 +28,7 @@ npm test
### Manual Complexity Assessment
Since Langflow does not have automated complexity analysis tools, assess components manually:
Since Hanzo Flow does not have automated complexity analysis tools, assess components manually:
1. **Count conditionals**: Each `if/else`, `switch/case`, ternary, `&&`/`||` chain adds +1.
2. **Count nesting levels**: Each level of nesting within conditionals or loops adds +1.
@@ -51,7 +51,7 @@ Since Langflow does not have automated complexity analysis tools, assess compone
**When**: Component has complex state management, multiple `useState`/`useEffect`, or business logic mixed with UI.
**Langflow Convention**: Place hooks in a `hooks/` subdirectory or alongside the component as `use-<feature>.ts`. Langflow uses kebab-case filenames with `use-` prefix.
**Hanzo Flow Convention**: Place hooks in a `hooks/` subdirectory or alongside the component as `use-<feature>.ts`. Hanzo Flow uses kebab-case filenames with `use-` prefix.
```typescript
// Before: Complex state logic in component
@@ -84,7 +84,7 @@ const FlowPage: FC = () => {
}
```
**Langflow Examples**:
**Hanzo Flow Examples**:
- `src/frontend/src/hooks/use-add-component.ts`
- `src/frontend/src/hooks/use-unsaved-changes.ts`
- `src/frontend/src/hooks/use-refresh-model-inputs.ts`
@@ -93,7 +93,7 @@ const FlowPage: FC = () => {
**When**: Single component has multiple UI sections, conditional rendering blocks, or repeated patterns.
**Langflow Convention**: Place sub-components in subdirectories or as separate files in the same directory. UI primitives go in `components/ui/`, domain components in `components/core/`, reusable components in `components/common/`.
**Hanzo Flow Convention**: Place sub-components in subdirectories or as separate files in the same directory. UI primitives go in `components/ui/`, domain components in `components/core/`, reusable components in `components/common/`.
```typescript
// Before: Monolithic JSX with multiple sections
@@ -126,7 +126,7 @@ const GenericNode = () => {
}
```
**Langflow Examples**:
**Hanzo Flow Examples**:
- `src/frontend/src/CustomNodes/GenericNode/components/`
- `src/frontend/src/components/core/`
- `src/frontend/src/components/ui/`
@@ -190,13 +190,13 @@ const getFieldComponent = (field: InputFieldType) => {
**When**: Component directly handles API calls, data transformation, or complex async operations.
**Langflow Convention**:
**Hanzo Flow Convention**:
- This skill is for component decomposition, not query/mutation design.
- When refactoring data fetching, use `frontend-query-mutation` for query patterns, `UseRequestProcessor`, cache invalidation, and mutation error handling.
- Do not create thin passthrough `useQuery` wrappers during refactoring; only extract a custom hook when it truly orchestrates multiple queries/mutations or shared derived state.
- API hooks live in `controllers/API/queries/{domain}/`.
**Langflow Examples**:
**Hanzo Flow Examples**:
- `src/frontend/src/controllers/API/queries/flows/use-post-add-flow.ts`
- `src/frontend/src/controllers/API/queries/variables/use-get-global-variables.ts`
- `src/frontend/src/controllers/API/queries/folders/use-get-folders.ts`
@@ -205,7 +205,7 @@ const getFieldComponent = (field: InputFieldType) => {
**When**: Component manages multiple modals with complex open/close states.
**Langflow Convention**: Modals should be extracted with their state management.
**Hanzo Flow Convention**: Modals should be extracted with their state management.
```typescript
// Before: Multiple modal states in component
@@ -239,7 +239,7 @@ const useFlowToolbarModals = () => {
**When**: Complex form validation, submission handling, or field transformation.
**Langflow Convention**: Extract form state and validation into hooks.
**Hanzo Flow Convention**: Extract form state and validation into hooks.
```typescript
// Extract form validation and submission
@@ -265,7 +265,7 @@ const useFlowSettingsForm = (initialValues: FlowSettings) => {
}
```
## Langflow-Specific Refactoring Guidelines
## Hanzo Flow-Specific Refactoring Guidelines
### 1. Zustand Store Selectors
@@ -286,7 +286,7 @@ const Component = () => {
}
```
**Langflow Reference**: All stores in `src/frontend/src/stores/` follow this selector pattern.
**Hanzo Flow Reference**: All stores in `src/frontend/src/stores/` follow this selector pattern.
### 2. Custom Node Components
@@ -419,7 +419,7 @@ const useButtonState = () => {
## References
### Langflow Codebase Examples
### Hanzo Flow Codebase Examples
- **Hook extraction**: `src/frontend/src/hooks/`
- **Component splitting**: `src/frontend/src/CustomNodes/GenericNode/components/`
@@ -1,12 +1,12 @@
# Complexity Reduction Patterns
This document provides patterns for reducing cognitive complexity in Langflow React components.
This document provides patterns for reducing cognitive complexity in Hanzo Flow React components.
## Understanding Complexity
### SonarJS Cognitive Complexity
Langflow does not have automated complexity analysis tools. Assess complexity manually using SonarJS cognitive complexity rules:
Hanzo Flow does not have automated complexity analysis tools. Assess complexity manually using SonarJS cognitive complexity rules:
- **Total Complexity**: Sum of all functions' complexity in the file
- **Max Complexity**: Highest single function complexity
@@ -1,6 +1,6 @@
# Component Splitting Patterns
This document provides detailed guidance on splitting large components into smaller, focused components in Langflow.
This document provides detailed guidance on splitting large components into smaller, focused components in Hanzo Flow.
## When to Split Components
@@ -563,11 +563,11 @@ function FieldList<T>({ fields, renderField, renderEmpty }: FieldListProps<T>) {
/>
```
## Langflow-Specific Splitting Guidelines
## Hanzo Flow-Specific Splitting Guidelines
### Splitting GenericNode Components
The `GenericNode` component is one of the most complex components in Langflow. When splitting:
The `GenericNode` component is one of the most complex components in Hanzo Flow. When splitting:
1. Keep the main `index.tsx` as an orchestrator that composes sub-components.
2. Parameter rendering goes in `components/NodeInputField/`.
@@ -1,6 +1,6 @@
# Hook Extraction Patterns
This document provides detailed guidance on extracting custom hooks from complex components in Langflow.
This document provides detailed guidance on extracting custom hooks from complex components in Hanzo Flow.
## When to Extract Hooks
@@ -138,7 +138,7 @@ const FlowPage: FC = () => {
- Use `use` prefix: `useFlowState`, `useNodeDrag`, `useBuildStatus`
- Be specific: `useRefreshModelInputs` not `useRefresh`
- Include domain: `useFlowStore`, `useGlobalVariables`, `useAddComponent`
- Match existing Langflow patterns: `useFlowsManagerStore`, `useFlowStore`
- Match existing Hanzo Flow patterns: `useFlowsManagerStore`, `useFlowStore`
### File Names
@@ -152,7 +152,7 @@ const FlowPage: FC = () => {
- Suffix with `Return`: `UseCanvasStateReturn`
- Suffix params with `Params`: `UseCanvasStateParams`
## Common Hook Patterns in Langflow
## Common Hook Patterns in Hanzo Flow
### 1. Zustand Store Derived State Hook
@@ -323,7 +323,7 @@ const [isExpanded, { toggle, setTrue: expand, setFalse: collapse }] = useToggle(
### 6. Keyboard Shortcut Hook
Langflow has keyboard shortcut support. Extract shortcut handling to hooks.
Hanzo Flow has keyboard shortcut support. Extract shortcut handling to hooks.
```typescript
// Pattern: Keyboard shortcut registration
+3 -3
View File
@@ -1,9 +1,9 @@
---
name: e2e-testing
description: Write and review Playwright E2E tests for Langflow. Trigger when the user asks to write, fix, or review E2E tests, spec files, Playwright tests, or integration tests that exercise the full UI. Also trigger when modifying data-testid attributes, test helpers in tests/utils/, or fixture configuration.
description: Write and review Playwright E2E tests for Hanzo Flow. Trigger when the user asks to write, fix, or review E2E tests, spec files, Playwright tests, or integration tests that exercise the full UI. Also trigger when modifying data-testid attributes, test helpers in tests/utils/, or fixture configuration.
---
# Langflow E2E Testing (Playwright)
# Hanzo Flow E2E Testing (Playwright)
## When to Apply
@@ -216,7 +216,7 @@ test("should show error on invalid input", { tag: ["@release"] }, async ({ page
### Priority (in order of preference)
1. **`getByTestId`** — Most stable, used 95% of the time in Langflow
1. **`getByTestId`** — Most stable, used 95% of the time in Hanzo Flow
2. **`getByRole`** — For buttons, headings, and form elements
3. **`getByText`** — For visible text content
4. **`waitForSelector`** — For CSS selectors and dynamic elements
@@ -2,7 +2,7 @@
## Overview
Langflow extends Playwright's default `test` and `expect` with a custom fixture in `src/frontend/tests/fixtures.ts`. This fixture adds **automatic error detection** that fails tests when unexpected API errors or flow execution errors occur.
Hanzo Flow extends Playwright's default `test` and `expect` with a custom fixture in `src/frontend/tests/fixtures.ts`. This fixture adds **automatic error detection** that fails tests when unexpected API errors or flow execution errors occur.
## Why Custom Fixtures Exist
@@ -153,7 +153,7 @@ withEventDeliveryModes(
);
```
Why: Langflow supports 3 event delivery modes. A bug that only appears in polling mode would be missed if tests only run in streaming mode. This helper ensures all modes are covered without writing 3x the tests.
Why: Hanzo Flow supports 3 event delivery modes. A bug that only appears in polling mode would be missed if tests only run in streaming mode. This helper ensures all modes are covered without writing 3x the tests.
## Advanced Patterns
@@ -170,7 +170,7 @@ Closes the old edit modal. **Deprecated**.
When to create a new helper:
- The same 5+ lines of setup appear in 3+ test files (DRY)
- The pattern involves complex waits or retries that are easy to get wrong
- The helper encapsulates Langflow-specific knowledge (e.g., global variable badge behavior)
- The helper encapsulates Hanzo Flow-specific knowledge (e.g., global variable badge behavior)
When NOT to create a helper:
- For a single test's setup (keep it inline)
@@ -1,6 +1,6 @@
# Langflow E2E Selector Catalog
# Hanzo Flow E2E Selector Catalog
This is the canonical reference for `data-testid` selectors used in Langflow E2E tests. When adding new interactive elements, follow these naming conventions and add the element to this catalog.
This is the canonical reference for `data-testid` selectors used in Hanzo Flow E2E tests. When adding new interactive elements, follow these naming conventions and add the element to this catalog.
## Naming Convention
+3 -3
View File
@@ -1,6 +1,6 @@
---
name: frontend-code-review
description: "Review frontend code (.tsx, .ts, .js files) for quality, performance, and correctness against Langflow's frontend conventions. Supports pending-change reviews and file-targeted reviews."
description: "Review frontend code (.tsx, .ts, .js files) for quality, performance, and correctness against Hanzo Flow's frontend conventions. Supports pending-change reviews and file-targeted reviews."
---
# Frontend Code Review
@@ -30,13 +30,13 @@ Notes when using this skill:
- Always include actionable fixes or suggestions (including possible code snippets).
- Use `File:Line` references when a file path and line numbers are available; otherwise, use the most specific identifier you can.
- The Langflow frontend uses React 19, TypeScript 5.4, Vite 7 with SWC, Zustand for state management, TanStack React Query for server state, @xyflow/react v12 for graph visualization, Radix UI + shadcn-ui components, Tailwind CSS v3, and Biome for linting/formatting.
- The Hanzo Flow frontend uses React 19, TypeScript 5.4, Vite 7 with SWC, Zustand for state management, TanStack React Query for server state, @xyflow/react v12 for graph visualization, Radix UI + shadcn-ui components, Tailwind CSS v3, and Biome for linting/formatting.
## Checklist
- **Code quality**: For any reviewed file, follow [references/code-quality.md](references/code-quality.md) to check styling conventions, TypeScript usage, Biome compliance, and component patterns.
- **Performance**: If the review scope involves React components, hooks, Zustand stores, React Query usage, or @xyflow/react node rendering, follow [references/performance.md](references/performance.md) to check for re-render issues, memoization, and data flow patterns.
- **Business logic**: If the review scope involves custom nodes (GenericNode), flow state, API calls, the component system, global variables, or the inspection panel, follow [references/business-logic.md](references/business-logic.md) to check for Langflow-specific correctness.
- **Business logic**: If the review scope involves custom nodes (GenericNode), flow state, API calls, the component system, global variables, or the inspection panel, follow [references/business-logic.md](references/business-logic.md) to check for Hanzo Flow-specific correctness.
## General Review Rules
@@ -59,7 +59,7 @@ Category: Business Logic
### Description
The Axios HTTP client in `src/frontend/src/controllers/API/` is configured with interceptors that handle authentication headers, token refresh, retry logic, and error normalization. Do not duplicate any of this logic in individual API call sites or components. Use the configured Axios instance (via the API controller helpers) for all backend requests. Do not create new Axios instances or use raw `fetch()` for API calls to the Langflow backend.
The Axios HTTP client in `src/frontend/src/controllers/API/` is configured with interceptors that handle authentication headers, token refresh, retry logic, and error normalization. Do not duplicate any of this logic in individual API call sites or components. Use the configured Axios instance (via the API controller helpers) for all backend requests. Do not create new Axios instances or use raw `fetch()` for API calls to the Hanzo Flow backend.
### Suggested Fix
@@ -197,7 +197,7 @@ Category: Business Logic
### Description
Langflow has a customization layer in `src/frontend/src/customization/` that allows overriding default behaviors and components. When adding new features that may need to be customized (e.g., branding, feature flags, custom components), use the customization layer rather than hardcoding values. Check `src/frontend/src/customization/` for existing customization points before adding new ones.
Hanzo Flow has a customization layer in `src/frontend/src/customization/` that allows overriding default behaviors and components. When adding new features that may need to be customized (e.g., branding, feature flags, custom components), use the customization layer rather than hardcoding values. Check `src/frontend/src/customization/` for existing customization points before adding new ones.
## React Hook Form + Zod for form validation
@@ -35,7 +35,7 @@ Category: Code Quality
Favor Tailwind CSS utility classes for all styling. Do not introduce new CSS modules or custom CSS files unless a Tailwind combination cannot achieve the required styling. Keeping styles in Tailwind improves consistency, reduces bundle size, and simplifies maintenance. The project uses Tailwind v3 with a custom theme configuration.
Why this matters: Introducing custom CSS files creates a parallel styling system that falls out of sync with Tailwind tokens. When the design team changes a border color, they update the CSS variable in `index.css` — but your CSS module keeps the old hardcoded color. Custom CSS also bypasses Tailwind's purging, increasing bundle size. In Langflow, with 300+ components sharing a design system, inconsistent styling compounds fast.
Why this matters: Introducing custom CSS files creates a parallel styling system that falls out of sync with Tailwind tokens. When the design team changes a border color, they update the CSS variable in `index.css` — but your CSS module keeps the old hardcoded color. Custom CSS also bypasses Tailwind's purging, increasing bundle size. In Hanzo Flow, with 300+ components sharing a design system, inconsistent styling compounds fast.
### Suggested Fix
@@ -179,7 +179,7 @@ Category: Code Quality
### Description
Never use `any` as a type annotation. Using `any` disables TypeScript's ability to catch type mismatches at compile time — bugs that would be caught by the compiler instead crash in production. In Langflow, flow data structures are deeply nested (`NodeDataType.node.template[fieldName].value`); an `any` at any level silently allows accessing non-existent properties, causing 'Cannot read properties of undefined' in the canvas. Use `unknown` with type guards for genuinely unknown data, or specific types/generics for everything else.
Never use `any` as a type annotation. Using `any` disables TypeScript's ability to catch type mismatches at compile time — bugs that would be caught by the compiler instead crash in production. In Hanzo Flow, flow data structures are deeply nested (`NodeDataType.node.template[fieldName].value`); an `any` at any level silently allows accessing non-existent properties, causing 'Cannot read properties of undefined' in the canvas. Use `unknown` with type guards for genuinely unknown data, or specific types/generics for everything else.
### Suggested Fix
@@ -228,7 +228,7 @@ Category: Code Quality
### Description
When building interactive UI elements (dialogs, dropdowns, tooltips, popovers, tabs, etc.), use Radix UI primitives via the shadcn-ui wrappers in `components/ui/`. Custom implementations of these patterns consistently miss: keyboard navigation (arrow keys in dropdowns), focus trapping (Tab stays inside dialogs), screen reader announcements (ARIA live regions), and Escape key handling. Rebuilding these from scratch introduces accessibility regressions that affect keyboard-only and screen reader users. Langflow is used by enterprise teams that may require WCAG compliance — every custom dropdown without proper focus management is a compliance risk.
When building interactive UI elements (dialogs, dropdowns, tooltips, popovers, tabs, etc.), use Radix UI primitives via the shadcn-ui wrappers in `components/ui/`. Custom implementations of these patterns consistently miss: keyboard navigation (arrow keys in dropdowns), focus trapping (Tab stays inside dialogs), screen reader announcements (ARIA live regions), and Escape key handling. Rebuilding these from scratch introduces accessibility regressions that affect keyboard-only and screen reader users. Hanzo Flow is used by enterprise teams that may require WCAG compliance — every custom dropdown without proper focus management is a compliance risk.
### Suggested Fix
@@ -298,7 +298,7 @@ Category: Code Quality
Do not leave `console.log`, `console.warn`, or `console.error` statements in production code. Biome enforces this rule. Use proper error handling, error boundaries, or toast notifications for user-facing errors. If logging is truly needed for debugging, remove it before committing.
Why: `console.log` in production code writes to the browser's developer console. In Langflow, component data often includes API keys stored in global variables — a `console.log(data)` accidentally leaks credentials to anyone who opens DevTools. Biome catches this at lint time; if Biome is not catching it, the linting step was skipped.
Why: `console.log` in production code writes to the browser's developer console. In Hanzo Flow, component data often includes API keys stored in global variables — a `console.log(data)` accidentally leaks credentials to anyone who opens DevTools. Biome catches this at lint time; if Biome is not catching it, the linting step was skipped.
## Prefer `const` and immutable patterns
@@ -333,7 +333,7 @@ Category: Code Quality
All React components must be functional components using hooks. Do not use class components, `React.Component`, or lifecycle methods (`componentDidMount`, etc.). Use `useEffect`, `useState`, `useMemo`, `useCallback`, and custom hooks instead.
Why: Class components have a larger API surface (lifecycle methods, `this` binding, constructor), making them harder to test and reason about. Hooks compose better — a custom hook can combine state, effects, and context without nesting HOCs. The entire Langflow codebase uses functional components; introducing a class component breaks consistency and forces other developers to context-switch between paradigms.
Why: Class components have a larger API surface (lifecycle methods, `this` binding, constructor), making them harder to test and reason about. Hooks compose better — a custom hook can combine state, effects, and context without nesting HOCs. The entire Hanzo Flow codebase uses functional components; introducing a class component breaks consistency and forces other developers to context-switch between paradigms.
## Early returns for guard clauses
@@ -378,7 +378,7 @@ Category: Code Quality
The project standardizes on Lucide React for icons. Do not import icons from other libraries (heroicons, react-icons, font-awesome, etc.) unless Lucide does not have an equivalent. Check the Lucide icon set first at https://lucide.dev before introducing a new icon dependency.
Why: Multiple icon libraries bloat the bundle (each library ships its own SVG set). Lucide is tree-shakeable — unused icons are removed at build time. Mixing libraries also creates visual inconsistency (different stroke widths, sizing conventions, visual weight). Langflow standardized on Lucide; check https://lucide.dev before adding a new dependency.
Why: Multiple icon libraries bloat the bundle (each library ships its own SVG set). Lucide is tree-shakeable — unused icons are removed at build time. Mixing libraries also creates visual inconsistency (different stroke widths, sizing conventions, visual weight). Hanzo Flow standardized on Lucide; check https://lucide.dev before adding a new dependency.
### Suggested Fix
@@ -169,7 +169,7 @@ Category: Performance
### Description
When reading from Zustand stores, always use selectors to subscribe to only the specific slices of state the component needs. Selecting the entire store object causes the component to re-render on every store update, even for unrelated state changes. Langflow has 15+ Zustand stores; careless subscriptions can create cascading performance problems.
When reading from Zustand stores, always use selectors to subscribe to only the specific slices of state the component needs. Selecting the entire store object causes the component to re-render on every store update, even for unrelated state changes. Hanzo Flow has 15+ Zustand stores; careless subscriptions can create cascading performance problems.
### Suggested Fix
@@ -1,6 +1,6 @@
---
name: frontend-query-mutation
description: Guide for implementing Langflow frontend query and mutation patterns with Axios and TanStack React Query v5. Trigger when creating or updating API hooks in controllers/API/queries, consuming UseRequestProcessor in components, deciding whether to use useQuery or useMutation, handling conditional queries, cache invalidation, mutation error handling, or migrating legacy API calls to the query hook pattern.
description: Guide for implementing Hanzo Flow frontend query and mutation patterns with Axios and TanStack React Query v5. Trigger when creating or updating API hooks in controllers/API/queries, consuming UseRequestProcessor in components, deciding whether to use useQuery or useMutation, handling conditional queries, cache invalidation, mutation error handling, or migrating legacy API calls to the query hook pattern.
---
# Frontend Query & Mutation
@@ -15,7 +15,7 @@ description: Guide for implementing Langflow frontend query and mutation pattern
## Architecture Overview
Langflow uses **Axios + TanStack React Query v5** for data fetching. There is no oRPC or contract layer. The architecture is:
Hanzo Flow uses **Axios + TanStack React Query v5** for data fetching. There is no oRPC or contract layer. The architecture is:
```
Component
@@ -48,7 +48,7 @@ Component
- Use the `api` Axios instance for all HTTP calls.
- Use `getURL()` for constructing API paths.
- Type the hook with `useQueryFunctionType` or `useMutationFunctionType`.
3. Preserve Langflow conventions.
3. Preserve Hanzo Flow conventions.
- Query keys are arrays with the hook name: `["useGetFlows"]`.
- Mutations invalidate related queries in `onSettled`.
- Zustand store updates happen in the query/mutation function, not in components.
@@ -69,4 +69,4 @@ Component
- Use `references/query-patterns.md` for hook structure, naming conventions, directory layout, and anti-patterns.
- Use `references/runtime-rules.md` for conditional queries, invalidation, `mutate` versus `mutateAsync`, error handling, and streaming requests.
Treat this skill as the single query and mutation entry point for Langflow frontend work. Keep detailed rules in the reference files instead of duplicating them in project docs.
Treat this skill as the single query and mutation entry point for Hanzo Flow frontend work. Keep detailed rules in the reference files instead of duplicating them in project docs.
@@ -139,11 +139,11 @@ export const useGetFolder: useQueryFunctionType<
### Important: Some "get" Hooks Use Mutation
In the Langflow codebase, some hooks named `use-get-*` (e.g., `useGetFlow`) are actually **mutation hooks** typed with `useMutationFunctionType`. This happens when the "get" operation is triggered imperatively (on demand) rather than declaratively (on mount/re-render). Check the actual type signature before following the query pattern — if a hook uses `mutate` from `UseRequestProcessor`, follow the Mutation Hook Structure below instead.
In the Hanzo Flow codebase, some hooks named `use-get-*` (e.g., `useGetFlow`) are actually **mutation hooks** typed with `useMutationFunctionType`. This happens when the "get" operation is triggered imperatively (on demand) rather than declaratively (on mount/re-render). Check the actual type signature before following the query pattern — if a hook uses `mutate` from `UseRequestProcessor`, follow the Mutation Hook Structure below instead.
### Query Hook with Store Updates
Many Langflow queries update Zustand stores as a side effect within the query function:
Many Hanzo Flow queries update Zustand stores as a side effect within the query function:
```typescript
export const useGetGlobalVariables: useQueryFunctionType<
@@ -330,7 +330,7 @@ When adding new endpoints, add the constant to `URLs` first, then use `getURL()`
## Query Keys
Query keys are arrays that uniquely identify cached data. Langflow conventions:
Query keys are arrays that uniquely identify cached data. Hanzo Flow conventions:
```typescript
// Hook name as key (no params)
@@ -12,7 +12,7 @@
## Conditional Queries
Use the `enabled` option to conditionally run queries. Langflow hooks pass through `options` to `UseRequestProcessor`, which passes them to `useQuery`.
Use the `enabled` option to conditionally run queries. Hanzo Flow hooks pass through `options` to `UseRequestProcessor`, which passes them to `useQuery`.
```typescript
// Pattern: Disable query when not authenticated
@@ -260,7 +260,7 @@ const { data, error, isError } = useGetFlow(
## Streaming Requests
Langflow uses `performStreamingRequest()` from `controllers/API/api.tsx` for build and chat streaming. This uses the browser `fetch` API (not Axios) with Server-Sent Events (SSE) parsing.
Hanzo Flow uses `performStreamingRequest()` from `controllers/API/api.tsx` for build and chat streaming. This uses the browser `fetch` API (not Axios) with Server-Sent Events (SSE) parsing.
### Streaming Architecture
+2 -2
View File
@@ -1,4 +1,4 @@
# Frontend Testing Skill - Langflow
# Frontend Testing Skill - Hanzo Flow
## When to Apply
@@ -290,7 +290,7 @@ npm test -- --coverage --collectCoverageFrom='src/path/to/file.ts' src/path/to/_
- [Async Testing](references/async-testing.md) - Patterns for async operations, timers, and waitFor
- [Common Patterns](references/common-patterns.md) - Query priority, events, forms, modals, data-driven tests
- [Test Checklist](references/checklist.md) - Pre-submission verification checklist
- [Domain Components](references/domain-components.md) - Langflow-specific component testing patterns
- [Domain Components](references/domain-components.md) - Hanzo Flow-specific component testing patterns
- [Component Template](assets/component-test.template.tsx) - Starter template for component tests
- [Hook Template](assets/hook-test.template.ts) - Starter template for hook tests
- [Utility Template](assets/utility-test.template.ts) - Starter template for utility tests
@@ -1,5 +1,5 @@
/**
* Test template for React components in Langflow.
* Test template for React components in Hanzo Flow.
*
* Usage:
* 1. Copy this file to `__tests__/ComponentName.test.tsx`
@@ -1,5 +1,5 @@
/**
* Test template for custom React hooks in Langflow.
* Test template for custom React hooks in Hanzo Flow.
*
* Usage:
* 1. Copy this file to `__tests__/use-hook-name.test.ts`
@@ -1,5 +1,5 @@
/**
* Test template for utility/helper functions in Langflow.
* Test template for utility/helper functions in Hanzo Flow.
*
* Usage:
* 1. Copy this file to `__tests__/util-name.test.ts`
@@ -1,6 +1,6 @@
# Async Testing Patterns
Patterns for testing asynchronous behavior in Langflow with Jest and React Testing Library.
Patterns for testing asynchronous behavior in Hanzo Flow with Jest and React Testing Library.
## waitFor
@@ -1,6 +1,6 @@
# Test Generation Checklist
Verify each item before submitting test code for Langflow frontend.
Verify each item before submitting test code for Hanzo Flow frontend.
## Pre-Writing
@@ -1,6 +1,6 @@
# Common Testing Patterns
Frequently used patterns for testing Langflow React components with Jest and React Testing Library.
Frequently used patterns for testing Hanzo Flow React components with Jest and React Testing Library.
## Query Priority
@@ -176,7 +176,7 @@ describe("LoginForm", () => {
## Modal/Dialog Testing
Langflow uses Radix UI dialogs:
Hanzo Flow uses Radix UI dialogs:
```typescript
describe("ConfirmDialog", () => {
@@ -316,7 +316,7 @@ describe("ItemList", () => {
## Testing Tooltips
Langflow uses Radix tooltips which require hover:
Hanzo Flow uses Radix tooltips which require hover:
```typescript
it("should show tooltip on hover", async () => {
@@ -363,7 +363,7 @@ describe("ErrorBoundary", () => {
## Testing Custom data-testid Attributes
Langflow components frequently use `data-testid` for testing. Common patterns:
Hanzo Flow components frequently use `data-testid` for testing. Common patterns:
```typescript
// Input components
@@ -1,10 +1,10 @@
# Domain-Specific Component Testing for Langflow
# Domain-Specific Component Testing for Hanzo Flow
Patterns for testing Langflow-specific components that have unique architectural concerns.
Patterns for testing Hanzo Flow-specific components that have unique architectural concerns.
## Flow/Graph Components
Langflow's flow editor is built on `@xyflow/react` (React Flow). These components require specific mocking strategies.
Hanzo Flow's flow editor is built on `@xyflow/react` (React Flow). These components require specific mocking strategies.
### GenericNode
@@ -581,13 +581,13 @@ describe("getPythonApiCode", () => {
});
```
## Testing Tips for Langflow Components
## Testing Tips for Hanzo Flow Components
1. **Node template data**: Create reusable mock node data objects. The template structure is deeply nested and used across many components.
2. **Store interdependencies**: Many components read from multiple stores (flowStore, typesStore, alertStore). Mock or initialize all relevant stores.
3. **data-testid conventions**: Langflow uses `data-testid` extensively. Common patterns:
3. **data-testid conventions**: Hanzo Flow uses `data-testid` extensively. Common patterns:
- `popover-anchor-input-{name}` for input fields
- `handle-{type}-{position}` for flow handles
- `sidebar-nav-{action}` for sidebar buttons
@@ -1,6 +1,6 @@
# Mocking Guide for Langflow Tests
# Mocking Guide for Hanzo Flow Tests
All mocking in Langflow uses Jest APIs. Never use Vitest (`vi.*`) APIs.
All mocking in Hanzo Flow uses Jest APIs. Never use Vitest (`vi.*`) APIs.
## Quick Reference
@@ -36,7 +36,7 @@ jest.unmock("@/stores/darkStore");
### Mocking Axios Calls
Langflow uses Axios via a configured API instance. Mock the API module:
Hanzo Flow uses Axios via a configured API instance. Mock the API module:
```typescript
import api from "@/controllers/API/api";
@@ -110,7 +110,7 @@ jest.mock("@/controllers/API", () => ({
## Zustand Store Mocking
Langflow does NOT have a global Zustand auto-mock. You have two options:
Hanzo Flow does NOT have a global Zustand auto-mock. You have two options:
### Option 1: Use Real Stores with `setState()` (Preferred)
@@ -210,7 +210,7 @@ describe("useMyStore", () => {
## React Router Mocking
Langflow uses `react-router-dom` v6 (NOT Next.js routing).
Hanzo Flow uses `react-router-dom` v6 (NOT Next.js routing).
### Wrapping with MemoryRouter
@@ -1,6 +1,6 @@
# Incremental Testing Workflow
Step-by-step process for systematically testing a directory of source files in Langflow.
Step-by-step process for systematically testing a directory of source files in Hanzo Flow.
## Phase 1: Discovery
+1 -1
View File
@@ -26,7 +26,7 @@ reviews:
poem: false
labeling_instructions: []
path_filters:
- "!src/backend/base/langflow/initial_setup/starter_projects"
- "!src/backend/base/flow/initial_setup/starter_projects"
path_instructions: []
abort_on_close: true
disable_cache: false
+7 -7
View File
@@ -6,21 +6,21 @@
# Config directory
# Directory where files, logs and database will be stored
# Example: HANZOFLOW_CONFIG_DIR=~/.langflow
# Example: HANZOFLOW_CONFIG_DIR=~/.flow
HANZOFLOW_CONFIG_DIR=
# Save database in the config directory
# Values: true, false
# If false, the database will be saved in Langflow's root directory
# This means that the database will be deleted when Langflow is uninstalled
# If false, the database will be saved in Hanzo Flow's root directory
# This means that the database will be deleted when Hanzo Flow is uninstalled
# and that the database will not be shared between different virtual environments
# Example: HANZOFLOW_SAVE_DB_IN_CONFIG_DIR=true
HANZOFLOW_SAVE_DB_IN_CONFIG_DIR=
# Database URL
# Postgres example: HANZOFLOW_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/langflow
# Postgres example: HANZOFLOW_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/flow
# SQLite example:
HANZOFLOW_DATABASE_URL=sqlite:///./langflow.db
HANZOFLOW_DATABASE_URL=sqlite:///./flow.db
# Alembic logs path flag. If set to true, Alembic will log to stdout.
LANGFLOW_ALEMBIC_LOG_TO_STDOUT=False
@@ -67,7 +67,7 @@ HANZOFLOW_PORT=
HANZOFLOW_LOG_LEVEL=
# Path to the log file
# Example: HANZOFLOW_LOG_FILE=logs/langflow.log
# Example: HANZOFLOW_LOG_FILE=logs/flow.log
HANZOFLOW_LOG_FILE=
# Time/Size for log to rotate
@@ -155,7 +155,7 @@ LANGFLOW_SSRF_ALLOWED_HOSTS=
LANGFLOW_MCP_COMPOSER_ENABLED=
# STORE_URL
# Example: HANZOFLOW_STORE_URL=https://api.langflow.store
# Example: HANZOFLOW_STORE_URL=https://api.flow.store
# HANZOFLOW_STORE_URL=
# DOWNLOAD_WEBHOOK_URL
+1 -1
View File
@@ -85,7 +85,7 @@ body:
required: true
- type: input
id: langflow-version
id: flow-version
attributes:
label: Hanzo Flow Version
placeholder: ex. 1.0.9
+2 -2
View File
@@ -1,4 +1,4 @@
self-hosted-runner:
labels:
- langflow-ai-arm64-40gb-ephemeral
- Langflow-runner
- flow-ai-arm64-40gb-ephemeral
- Hanzo Flow-runner
+21 -21
View File
@@ -11,11 +11,11 @@ python:
- ".github/workflows/ci.yml"
- "src/lfx/src/lfx/_assets/component_index.json"
components-changes:
- "src/backend/base/langflow/components/**"
- "src/backend/base/flow/components/**"
- "src/lfx/src/lfx/components/**"
- "src/lfx/src/lfx/_assets/component_index.json"
starter-projects-changes:
- "src/backend/base/langflow/initial_setup/**"
- "src/backend/base/flow/initial_setup/**"
frontend-tests:
- "src/frontend/tests/**"
frontend:
@@ -38,16 +38,16 @@ docker:
# Test categories and their associated paths
starter-projects:
- "src/backend/base/langflow/initial_setup/**"
- "src/backend/base/langflow/components/**"
- "src/backend/base/langflow/services/**"
- "src/backend/base/langflow/custom/**"
- "src/backend/base/langflow/api/v1/chat.py"
- "src/backend/base/flow/initial_setup/**"
- "src/backend/base/flow/components/**"
- "src/backend/base/flow/services/**"
- "src/backend/base/flow/custom/**"
- "src/backend/base/flow/api/v1/chat.py"
- "src/frontend/src/pages/MainPage/**"
- "src/frontend/src/utils/reactflowUtils.ts"
- "src/frontend/tests/extended/features/**"
- "src/backend/base/langflow/custom/**"
- "src/backend/base/langflow/graph/**"
- "src/backend/base/flow/custom/**"
- "src/backend/base/flow/graph/**"
components:
- "src/frontend/src/components/**"
@@ -64,14 +64,14 @@ components:
- "src/frontend/tests/extended/integrations/**"
- "src/frontend/tests/extended/features/**"
- "src/frontend/tests/extended/regression/**"
- "src/backend/base/langflow/custom/**"
- "src/backend/base/langflow/schema/**"
- "src/backend/base/langflow/graph/**"
- "src/backend/base/langflow/utils/**"
- "src/backend/base/langflow/custom/**"
- "src/backend/base/langflow/components/**"
- "src/backend/base/langflow/initial_setup/**"
- "src/backend/base/langflow/serialization/**"
- "src/backend/base/flow/custom/**"
- "src/backend/base/flow/schema/**"
- "src/backend/base/flow/graph/**"
- "src/backend/base/flow/utils/**"
- "src/backend/base/flow/custom/**"
- "src/backend/base/flow/components/**"
- "src/backend/base/flow/initial_setup/**"
- "src/backend/base/flow/serialization/**"
- "src/lfx/src/lfx/components/**"
- "src/lfx/src/lfx/custom/**"
- "src/lfx/src/lfx/schema/**"
@@ -79,7 +79,7 @@ components:
- "src/lfx/src/lfx/_assets/component_index.json"
workspace:
- "src/backend/base/langflow/inputs/**"
- "src/backend/base/flow/inputs/**"
- "src/lfx/src/lfx/inputs/**"
- "src/frontend/src/components/core/parameterRenderComponent/**"
- "src/frontend/src/CustomNodes/**"
@@ -94,15 +94,15 @@ workspace:
- "src/frontend/tests/core/regression/**"
api:
- "src/backend/base/langflow/api/**"
- "src/backend/base/flow/api/**"
- "src/frontend/src/controllers/**"
- "src/frontend/tests/core/features/**"
- "src/frontend/tests/extended/features/**"
- "src/frontend/tests/extended/regression/**"
database:
- "src/backend/base/langflow/services/database/**"
- "src/backend/base/langflow/alembic/**"
- "src/backend/base/flow/services/database/**"
- "src/backend/base/flow/alembic/**"
- "src/frontend/src/controllers/**"
- "src/frontend/tests/core/features/**"
- "src/frontend/tests/extended/features/**"
+3 -3
View File
@@ -58,7 +58,7 @@ on:
options:
- ubuntu-latest
- self-hosted
- '["self-hosted", "linux", "ARM64", "langflow-ai-arm64-40gb-ephemeral"]'
- '["self-hosted", "linux", "ARM64", "flow-ai-arm64-40gb-ephemeral"]'
default: ubuntu-latest
pull_request:
types: [opened, synchronize, labeled]
@@ -117,8 +117,8 @@ jobs:
TODAY=$(date -u +"%Y-%m-%d")
echo "Today's date: $TODAY"
# Query PyPI API for the langflow package
HTTP_STATUS=$(curl -s -o response.json -w "%{http_code}" https://pypi.org/pypi/langflow-nightly/json)
# Query PyPI API for the flow package
HTTP_STATUS=$(curl -s -o response.json -w "%{http_code}" https://pypi.org/pypi/flow-nightly/json)
# Check HTTP status code first
if [ "$HTTP_STATUS" -ne 200 ]; then
+1 -1
View File
@@ -3,7 +3,7 @@ name: Codeflash
on:
pull_request:
paths:
- "src/backend/base/langflow/**"
- "src/backend/base/flow/**"
workflow_dispatch:
concurrency:
+12 -12
View File
@@ -1,11 +1,11 @@
# Cross-Platform Install Tests
Unified workflow for testing langflow installation across multiple platforms, supporting both manual and programmatic execution.
Unified workflow for testing flow installation across multiple platforms, supporting both manual and programmatic execution.
## Manual Testing
### 1. Test from PyPI
Tests published langflow packages from PyPI across all platforms.
Tests published flow packages from PyPI across all platforms.
**Via GitHub UI:**
1. Go to **Actions** → **Cross-Platform Installation Test**
@@ -21,11 +21,11 @@ gh workflow run cross-platform-test.yml -f test-from-pypi=true
# Test specific version
gh workflow run cross-platform-test.yml \
-f test-from-pypi=true \
-f langflow-version="1.0.18"
-f flow-version="1.0.18"
```
### 2. Test from Source
Builds and tests langflow from current branch source code using release-like dependency resolution (transforms workspace dependencies to published packages for testing parity).
Builds and tests flow from current branch source code using release-like dependency resolution (transforms workspace dependencies to published packages for testing parity).
**Via GitHub UI:**
1. Go to **Actions** → **Cross-Platform Installation Test**
@@ -64,11 +64,11 @@ jobs:
## What Gets Tested
1. **Package Installation**: `uv pip install langflow` (PyPI) or local wheel installation
1. **Package Installation**: `uv pip install flow` (PyPI) or local wheel installation
2. **Dependencies**: Additional packages like `openai` for full functionality
3. **CLI Help**: `langflow --help`
4. **Server Startup**: `langflow run --backend-only` with `/health_check` endpoint validation
5. **Python Import**: `import langflow`
3. **CLI Help**: `flow --help`
4. **Server Startup**: `flow run --backend-only` with `/health_check` endpoint validation
5. **Python Import**: `import flow`
## Common Options
@@ -80,7 +80,7 @@ gh workflow run cross-platform-test.yml \
# Test specific PyPI version
gh workflow run cross-platform-test.yml \
-f test-from-pypi=true \
-f langflow-version="1.0.18"
-f flow-version="1.0.18"
```
## Use Cases
@@ -176,13 +176,13 @@ error: command '/usr/bin/clang++' failed with exit code 1
| Build Type | Package Source | Dependencies | chromadb | Result |
|------------|----------------|--------------|----------|---------|
| **Manual/Source** | Workspace (`langflow-base = { workspace = true }`) | 162 packages | ❌ Not included | ✅ Success |
| **Nightly/Release** | Published (`langflow-base-nightly==0.5.0.dev21`) | 420 packages | ✅ Included | ❌ Compilation fails |
| **Manual/Source** | Workspace (`flow-base = { workspace = true }`) | 162 packages | ❌ Not included | ✅ Success |
| **Nightly/Release** | Published (`flow-base-nightly==0.5.0.dev21`) | 420 packages | ✅ Included | ❌ Compilation fails |
**Technical Details**:
1. **Workspace builds** use local `src/backend/base/pyproject.toml` which excludes `chromadb`
2. **Nightly builds** modify dependencies via `scripts/ci/update_uv_dependency.py`:
- Changes: `langflow-base~=0.5.0` → `langflow-base-nightly==0.5.0.dev21`
- Changes: `flow-base~=0.5.0` → `flow-base-nightly==0.5.0.dev21`
- Uses published PyPI package with full dependency tree including `chromadb==0.5.23`
3. **macOS clang** doesn't support `-march=native` flag used by `chroma-hnswlib` compilation
+54 -54
View File
@@ -3,8 +3,8 @@ name: Cross-Platform Installation Test
on:
workflow_dispatch:
inputs:
langflow-version:
description: "Langflow version to test from PyPI (leave empty to test from source)"
flow-version:
description: "Hanzo Flow version to test from PyPI (leave empty to test from source)"
required: false
type: string
default: ""
@@ -27,7 +27,7 @@ jobs:
build-if-needed:
name: Build Packages (if no artifacts provided)
runs-on: ubuntu-latest
if: inputs.langflow-version == '' && contains(github.workflow_ref, 'cross-platform-test.yml')
if: inputs.flow-version == '' && contains(github.workflow_ref, 'cross-platform-test.yml')
outputs:
base-artifact-name: ${{ steps.set-names.outputs.base-artifact-name }}
main-artifact-name: ${{ steps.set-names.outputs.main-artifact-name }}
@@ -175,7 +175,7 @@ jobs:
id: install-method
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
if [ -n "${{ inputs.langflow-version }}" ]; then
if [ -n "${{ inputs.flow-version }}" ]; then
echo "method=pypi" >> $GITHUB_OUTPUT
else
echo "method=wheel" >> $GITHUB_OUTPUT
@@ -209,7 +209,7 @@ jobs:
shell: bash
# Download artifacts for wheel installation
- name: Download langflow-sdk package artifact
- name: Download flow-sdk package artifact
if: steps.install-method.outputs.method == 'wheel' && (inputs.sdk-artifact-name != '' || needs.build-if-needed.outputs.sdk-artifact-name != '')
uses: actions/download-artifact@v8
with:
@@ -280,7 +280,7 @@ jobs:
printf 'Installing %s wheel(s):\n' "$label"
printf '%s\n' "$@"
refresh_find_links
# Use `if-necessary-or-explicit` (not `allow`): nightly langflow* wheels
# Use `if-necessary-or-explicit` (not `allow`): nightly flow* wheels
# are .dev pre-releases so we need to allow them explicitly, but `allow`
# leaks to transitive deps and resolves pre-release pydantic alphas
# (e.g. 2.14.0a1) which break langchain-core's module-level
@@ -305,9 +305,9 @@ jobs:
MAIN_WHEELS=()
while IFS= read -r wheel; do
MAIN_WHEELS+=("$wheel")
done < <(find ./main-dist -name "langflow*.whl" ! -name "langflow_base*.whl" -type f | sort)
done < <(find ./main-dist -name "flow*.whl" ! -name "langflow_base*.whl" -type f | sort)
if [ ${#MAIN_WHEELS[@]} -ne 1 ]; then
echo "Expected exactly one langflow wheel in ./main-dist, found ${#MAIN_WHEELS[@]}"
echo "Expected exactly one flow wheel in ./main-dist, found ${#MAIN_WHEELS[@]}"
find ./main-dist -name "*.whl" -type f | sort
exit 1
fi
@@ -315,23 +315,23 @@ jobs:
shell: bash
# PyPI installation steps
- name: Install langflow from PyPI (Windows)
- name: Install flow from PyPI (Windows)
if: steps.install-method.outputs.method == 'pypi' && matrix.os == 'windows'
run: |
if [ -n "${{ inputs.langflow-version }}" ]; then
uv pip install --python ./test-env/Scripts/python.exe langflow==${{ inputs.langflow-version }}
if [ -n "${{ inputs.flow-version }}" ]; then
uv pip install --python ./test-env/Scripts/python.exe flow==${{ inputs.flow-version }}
else
uv pip install --python ./test-env/Scripts/python.exe langflow
uv pip install --python ./test-env/Scripts/python.exe flow
fi
shell: bash
- name: Install langflow from PyPI (Unix)
- name: Install flow from PyPI (Unix)
if: steps.install-method.outputs.method == 'pypi' && matrix.os != 'windows'
run: |
if [ -n "${{ inputs.langflow-version }}" ]; then
uv pip install --python ./test-env/bin/python langflow==${{ inputs.langflow-version }}
if [ -n "${{ inputs.flow-version }}" ]; then
uv pip install --python ./test-env/bin/python flow==${{ inputs.flow-version }}
else
uv pip install --python ./test-env/bin/python langflow
uv pip install --python ./test-env/bin/python flow
fi
shell: bash
@@ -352,13 +352,13 @@ jobs:
- name: Test CLI help command
if: matrix.os == 'windows'
run: |
uv run --python ./test-env/Scripts/python.exe python -m langflow --help
uv run --python ./test-env/Scripts/python.exe python -m flow --help
shell: cmd
- name: Test CLI help command (Unix)
if: matrix.os != 'windows'
run: |
uv run --python ./test-env/bin/python python -m langflow --help
uv run --python ./test-env/bin/python python -m flow --help
shell: bash
- name: Test server startup (Windows)
@@ -366,7 +366,7 @@ jobs:
timeout-minutes: 5
run: |
# Start server in background
$serverProcess = Start-Process -FilePath ".\test-env\Scripts\python.exe" -ArgumentList "-m", "langflow", "run", "--host", "localhost", "--port", "7860", "--backend-only" -PassThru -WindowStyle Hidden
$serverProcess = Start-Process -FilePath ".\test-env\Scripts\python.exe" -ArgumentList "-m", "flow", "run", "--host", "localhost", "--port", "7860", "--backend-only" -PassThru -WindowStyle Hidden
# Wait for server to be ready (GitHub Actions will timeout after 5 minutes)
do {
@@ -392,7 +392,7 @@ jobs:
OBJC_DISABLE_INITIALIZE_FORK_SAFETY: YES
run: |
# Start server in background
./test-env/bin/python -m langflow run --host localhost --port 7860 --backend-only &
./test-env/bin/python -m flow run --host localhost --port 7860 --backend-only &
SERVER_PID=$!
# Wait for server to be ready (GitHub Actions will timeout after 5 minutes)
@@ -414,10 +414,10 @@ jobs:
run: |
test-env\Scripts\python.exe -c "
try:
import langflow
print('✅ langflow import successful on ${{ matrix.os }}-${{ matrix.arch }}')
import flow
print('✅ flow import successful on ${{ matrix.os }}-${{ matrix.arch }}')
except Exception as e:
print(f'❌ langflow import failed on ${{ matrix.os }}-${{ matrix.arch }}: {e}')
print(f'❌ flow import failed on ${{ matrix.os }}-${{ matrix.arch }}: {e}')
exit(1)
"
shell: cmd
@@ -427,10 +427,10 @@ jobs:
run: |
./test-env/bin/python -c "
try:
import langflow
print('✅ langflow import successful on ${{ matrix.os }}-${{ matrix.arch }}')
import flow
print('✅ flow import successful on ${{ matrix.os }}-${{ matrix.arch }}')
except Exception as e:
print(f'❌ langflow import failed on ${{ matrix.os }}-${{ matrix.arch }}: {e}')
print(f'❌ flow import failed on ${{ matrix.os }}-${{ matrix.arch }}: {e}')
exit(1)
"
shell: bash
@@ -468,7 +468,7 @@ jobs:
id: install-method
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
if [ -n "${{ inputs.langflow-version }}" ]; then
if [ -n "${{ inputs.flow-version }}" ]; then
echo "method=pypi" >> $GITHUB_OUTPUT
else
echo "method=wheel" >> $GITHUB_OUTPUT
@@ -502,7 +502,7 @@ jobs:
shell: bash
# Download artifacts for wheel installation
- name: Download langflow-sdk package artifact
- name: Download flow-sdk package artifact
if: steps.install-method.outputs.method == 'wheel' && (inputs.sdk-artifact-name != '' || needs.build-if-needed.outputs.sdk-artifact-name != '')
uses: actions/download-artifact@v8
with:
@@ -594,9 +594,9 @@ jobs:
MAIN_WHEELS=()
while IFS= read -r wheel; do
MAIN_WHEELS+=("$wheel")
done < <(find ./main-dist -name "langflow*.whl" ! -name "langflow_base*.whl" -type f | sort)
done < <(find ./main-dist -name "flow*.whl" ! -name "langflow_base*.whl" -type f | sort)
if [ ${#MAIN_WHEELS[@]} -ne 1 ]; then
echo "Expected exactly one langflow wheel in ./main-dist, found ${#MAIN_WHEELS[@]}"
echo "Expected exactly one flow wheel in ./main-dist, found ${#MAIN_WHEELS[@]}"
find ./main-dist -name "*.whl" -type f | sort
exit 1
fi
@@ -617,7 +617,7 @@ jobs:
SDK_WHEEL=$(find ./sdk-dist -name "*.whl" -type f | head -1)
fi
if [ -n "$SDK_WHEEL" ]; then
echo "Force reinstalling langflow-sdk with LFX: $SDK_WHEEL"
echo "Force reinstalling flow-sdk with LFX: $SDK_WHEEL"
INSTALL_WHEELS=("$SDK_WHEEL" "$LFX_WHEEL")
fi
NO_DEPS="--no-deps"
@@ -631,7 +631,7 @@ jobs:
# Reinstall base
BASE_WHEEL=$(find ./base-dist -name "*.whl" -type f | head -1)
if [ -n "$BASE_WHEEL" ]; then
echo "Force reinstalling langflow-base: $BASE_WHEEL"
echo "Force reinstalling flow-base: $BASE_WHEEL"
NO_DEPS="--no-deps"
if [ "${{ inputs.pre_release }}" = "true" ]; then
NO_DEPS=""
@@ -654,7 +654,7 @@ jobs:
SDK_WHEEL=$(find ./sdk-dist -name "*.whl" -type f | head -1)
fi
if [ -n "$SDK_WHEEL" ]; then
echo "Force reinstalling langflow-sdk with LFX: $SDK_WHEEL"
echo "Force reinstalling flow-sdk with LFX: $SDK_WHEEL"
INSTALL_WHEELS=("$SDK_WHEEL" "$LFX_WHEEL")
fi
NO_DEPS="--no-deps"
@@ -668,7 +668,7 @@ jobs:
# Reinstall base
BASE_WHEEL=$(find ./base-dist -name "*.whl" -type f | head -1)
if [ -n "$BASE_WHEEL" ]; then
echo "Force reinstalling langflow-base: $BASE_WHEEL"
echo "Force reinstalling flow-base: $BASE_WHEEL"
NO_DEPS="--no-deps"
if [ "${{ inputs.pre_release }}" = "true" ]; then
NO_DEPS=""
@@ -678,23 +678,23 @@ jobs:
shell: bash
# PyPI installation steps
- name: Install langflow from PyPI (Windows)
- name: Install flow from PyPI (Windows)
if: steps.install-method.outputs.method == 'pypi' && matrix.os == 'windows'
run: |
if [ -n "${{ inputs.langflow-version }}" ]; then
uv pip install --python ./test-env/Scripts/python.exe langflow==${{ inputs.langflow-version }}
if [ -n "${{ inputs.flow-version }}" ]; then
uv pip install --python ./test-env/Scripts/python.exe flow==${{ inputs.flow-version }}
else
uv pip install --python ./test-env/Scripts/python.exe langflow
uv pip install --python ./test-env/Scripts/python.exe flow
fi
shell: bash
- name: Install langflow from PyPI (Unix)
- name: Install flow from PyPI (Unix)
if: steps.install-method.outputs.method == 'pypi' && matrix.os != 'windows'
run: |
if [ -n "${{ inputs.langflow-version }}" ]; then
uv pip install --python ./test-env/bin/python langflow==${{ inputs.langflow-version }}
if [ -n "${{ inputs.flow-version }}" ]; then
uv pip install --python ./test-env/bin/python flow==${{ inputs.flow-version }}
else
uv pip install --python ./test-env/bin/python langflow
uv pip install --python ./test-env/bin/python flow
fi
shell: bash
@@ -715,13 +715,13 @@ jobs:
- name: Test CLI help command (Windows)
if: matrix.os == 'windows'
run: |
uv run --python ./test-env/Scripts/python.exe python -m langflow --help
uv run --python ./test-env/Scripts/python.exe python -m flow --help
shell: cmd
- name: Test CLI help command (Unix)
if: matrix.os != 'windows'
run: |
uv run --python ./test-env/bin/python python -m langflow --help
uv run --python ./test-env/bin/python python -m flow --help
shell: bash
- name: Test server startup (Windows)
@@ -729,7 +729,7 @@ jobs:
timeout-minutes: 5
run: |
# Start server in background
$serverProcess = Start-Process -FilePath ".\test-env\Scripts\python.exe" -ArgumentList "-m", "langflow", "run", "--host", "localhost", "--port", "7860", "--backend-only" -PassThru -WindowStyle Hidden
$serverProcess = Start-Process -FilePath ".\test-env\Scripts\python.exe" -ArgumentList "-m", "flow", "run", "--host", "localhost", "--port", "7860", "--backend-only" -PassThru -WindowStyle Hidden
# Wait for server to be ready (GitHub Actions will timeout after 5 minutes)
do {
@@ -755,7 +755,7 @@ jobs:
OBJC_DISABLE_INITIALIZE_FORK_SAFETY: YES
run: |
# Start server in background
./test-env/bin/python -m langflow run --host localhost --port 7860 --backend-only &
./test-env/bin/python -m flow run --host localhost --port 7860 --backend-only &
SERVER_PID=$!
# Wait for server to be ready (GitHub Actions will timeout after 5 minutes)
@@ -777,10 +777,10 @@ jobs:
run: |
test-env\Scripts\python.exe -c "
try:
import langflow
print('✅ langflow import successful on ${{ matrix.os }}-${{ matrix.arch }}')
import flow
print('✅ flow import successful on ${{ matrix.os }}-${{ matrix.arch }}')
except Exception as e:
print(f'❌ langflow import failed on ${{ matrix.os }}-${{ matrix.arch }}: {e}')
print(f'❌ flow import failed on ${{ matrix.os }}-${{ matrix.arch }}: {e}')
exit(1)
"
shell: cmd
@@ -790,10 +790,10 @@ jobs:
run: |
./test-env/bin/python -c "
try:
import langflow
print('✅ langflow import successful on ${{ matrix.os }}-${{ matrix.arch }}')
import flow
print('✅ flow import successful on ${{ matrix.os }}-${{ matrix.arch }}')
except Exception as e:
print(f'❌ langflow import failed on ${{ matrix.os }}-${{ matrix.arch }}: {e}')
print(f'❌ flow import failed on ${{ matrix.os }}-${{ matrix.arch }}: {e}')
exit(1)
"
shell: bash
@@ -816,7 +816,7 @@ jobs:
if [ "$stable_result" = "success" ]; then
if [ "$experimental_result" = "success" ]; then
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
if [ -n "${{ inputs.langflow-version }}" ]; then
if [ -n "${{ inputs.flow-version }}" ]; then
echo "✅ All PyPI installation tests passed (including Python 3.13)"
else
echo "✅ All source build and installation tests passed (including Python 3.13)"
@@ -826,7 +826,7 @@ jobs:
fi
else
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
if [ -n "${{ inputs.langflow-version }}" ]; then
if [ -n "${{ inputs.flow-version }}" ]; then
echo "✅ PyPI installation tests passed (Python 3.13 experimental failures are acceptable)"
else
echo "✅ Source build and installation tests passed (Python 3.13 experimental failures are acceptable)"
+59 -59
View File
@@ -10,16 +10,16 @@ on:
workflow_dispatch:
inputs:
nightly_tag:
description: "Nightly tag to test migration to (e.g., langflowai/langflow-nightly:latest)"
description: "Nightly tag to test migration to (e.g., langflowai/flow-nightly:latest)"
required: false
type: string
default: "langflowai/langflow-nightly:latest"
default: "langflowai/flow-nightly:latest"
# Note: This workflow is called by nightly_build.yml after Docker images are built
env:
PYTHON_VERSION: "3.13"
POSTGRES_DB: langflow_test
POSTGRES_USER: langflow
POSTGRES_USER: flow
POSTGRES_PASSWORD: langflow_test_pass # pragma: allowlist secret
jobs:
@@ -59,16 +59,16 @@ jobs:
mkdir -p migration-test
cd migration-test
- name: Install latest stable Langflow with PostgreSQL
- name: Install latest stable Hanzo Flow with PostgreSQL
working-directory: migration-test
run: |
echo "Installing latest stable langflow[postgresql]..."
echo "Installing latest stable flow[postgresql]..."
uv venv
source .venv/bin/activate
uv pip install "langflow[postgresql]"
uv pip install "flow[postgresql]"
# Verify installation
python -c 'from importlib.metadata import version; print("Installed Langflow version:", version("langflow"))'
python -c 'from importlib.metadata import version; print("Installed Hanzo Flow version:", version("flow"))'
- name: Initialize database with stable version
working-directory: migration-test
@@ -77,10 +77,10 @@ jobs:
run: |
source .venv/bin/activate
echo "Starting Langflow to initialize database..."
echo "Starting Hanzo Flow to initialize database..."
# shellcheck disable=SC2016
timeout 120 bash -c '
python -m langflow run --host 127.0.0.1 --port 7860 --backend-only &
python -m flow run --host 127.0.0.1 --port 7860 --backend-only &
LANGFLOW_PID=$!
until curl -f http://127.0.0.1:7860/health_check 2>/dev/null; do
sleep 2
@@ -88,7 +88,7 @@ jobs:
kill $LANGFLOW_PID
wait $LANGFLOW_PID 2>/dev/null || true
' || {
echo "Failed to start Langflow stable version"
echo "Failed to start Hanzo Flow stable version"
exit 1
}
@@ -101,8 +101,8 @@ jobs:
run: |
source .venv/bin/activate
# Start Langflow briefly to create test data
python -m langflow run --host 127.0.0.1 --port 7860 --backend-only &
# Start Hanzo Flow briefly to create test data
python -m flow run --host 127.0.0.1 --port 7860 --backend-only &
LANGFLOW_PID=$!
# Wait for startup
@@ -147,7 +147,7 @@ jobs:
fi
echo "✅ Witness credential created successfully"
# Stop Langflow
# Stop Hanzo Flow
kill $LANGFLOW_PID
wait $LANGFLOW_PID 2>/dev/null || true
@@ -158,18 +158,18 @@ jobs:
run: |
source .venv/bin/activate
NIGHTLY_TAG="${{ inputs.nightly_tag || 'langflowai/langflow-nightly:latest' }}"
NIGHTLY_TAG="${{ inputs.nightly_tag || 'langflowai/flow-nightly:latest' }}"
echo "Upgrading to nightly version: $NIGHTLY_TAG"
# Remove stable distributions before installing nightly.
# langflow and langflow-nightly share langflow-base which writes to the
# same site-packages/langflow/ namespace. If stable stays installed,
# python -m langflow still boots the stable version and no real
# flow and flow-nightly share flow-base which writes to the
# same site-packages/flow/ namespace. If stable stays installed,
# python -m flow still boots the stable version and no real
# nightly migration is exercised (false-positive test).
echo "Removing stable langflow to avoid namespace collision with nightly..."
uv pip uninstall -y langflow langflow-base || true
echo "Removing stable flow to avoid namespace collision with nightly..."
uv pip uninstall -y flow flow-base || true
# Extract version from Docker tag (format: langflowai/langflow-nightly:v1.10.0.dev20260522)
# Extract version from Docker tag (format: langflowai/flow-nightly:v1.10.0.dev20260522)
if [[ "$NIGHTLY_TAG" == *":"* ]]; then
VERSION="${NIGHTLY_TAG##*:}"
echo "Extracted version from tag: $VERSION"
@@ -180,19 +180,19 @@ jobs:
if [[ "$VERSION" == "latest" ]]; then
# Install latest nightly from PyPI
uv pip install --upgrade 'langflow-nightly[postgresql]'
uv pip install --upgrade 'flow-nightly[postgresql]'
else
# Install specific version
uv pip install --upgrade "langflow-nightly[postgresql]==$VERSION"
uv pip install --upgrade "flow-nightly[postgresql]==$VERSION"
fi
else
# Direct version string (strip 'v' prefix if present)
VERSION="${NIGHTLY_TAG#v}"
uv pip install --upgrade "langflow-nightly[postgresql]==$VERSION"
uv pip install --upgrade "flow-nightly[postgresql]==$VERSION"
fi
# Verify upgrade
python -c 'from importlib.metadata import version; print("Upgraded to Langflow Nightly version:", version("langflow-nightly"))'
python -c 'from importlib.metadata import version; print("Upgraded to Hanzo Flow Nightly version:", version("flow-nightly"))'
- name: Run migration and verify startup
working-directory: migration-test
@@ -201,26 +201,26 @@ jobs:
run: |
source .venv/bin/activate
echo "Starting Langflow nightly to run migrations..."
echo "Starting Hanzo Flow nightly to run migrations..."
# shellcheck disable=SC2016
timeout 180 bash -c '
python -m langflow run --host 127.0.0.1 --port 7860 --backend-only > langflow_nightly.log 2>&1 &
python -m flow run --host 127.0.0.1 --port 7860 --backend-only > langflow_nightly.log 2>&1 &
LANGFLOW_PID=$!
until curl -f http://127.0.0.1:7860/health_check 2>/dev/null; do
if ! kill -0 $LANGFLOW_PID 2>/dev/null; then
echo "Langflow process died during startup"
echo "Hanzo Flow process died during startup"
cat langflow_nightly.log
exit 1
fi
sleep 2
done
echo "Langflow nightly started successfully"
echo "Hanzo Flow nightly started successfully"
kill $LANGFLOW_PID
wait $LANGFLOW_PID 2>/dev/null || true
' || {
echo "Failed to start Langflow nightly version"
echo "Failed to start Hanzo Flow nightly version"
cat langflow_nightly.log || true
exit 1
}
@@ -232,8 +232,8 @@ jobs:
run: |
source .venv/bin/activate
# Start Langflow to query data
python -m langflow run --host 127.0.0.1 --port 7860 --backend-only &
# Start Hanzo Flow to query data
python -m flow run --host 127.0.0.1 --port 7860 --backend-only &
LANGFLOW_PID=$!
timeout 60 bash -c 'until curl -f http://127.0.0.1:7860/health_check 2>/dev/null; do sleep 2; done'
@@ -305,12 +305,12 @@ jobs:
run: | # pragma: allowlist secret
cat > docker-compose.yml <<'EOF'
services:
langflow:
image: langflowai/langflow:latest
flow:
image: langflowai/flow:latest
ports:
- "7860:7860"
environment: # pragma: allowlist secret
- LANGFLOW_DATABASE_URL=postgresql://langflow:langflow@postgres:5432/langflow # pragma: allowlist secret
- LANGFLOW_DATABASE_URL=postgresql://flow:flow@postgres:5432/flow # pragma: allowlist secret
depends_on:
postgres:
condition: service_healthy
@@ -323,13 +323,13 @@ jobs:
postgres:
image: postgres:16
environment: # pragma: allowlist secret
- POSTGRES_USER=langflow
- POSTGRES_PASSWORD=langflow # pragma: allowlist secret
- POSTGRES_DB=langflow
- POSTGRES_USER=flow
- POSTGRES_PASSWORD=flow # pragma: allowlist secret
- POSTGRES_DB=flow
volumes:
- langflow_postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U langflow"]
test: ["CMD-SHELL", "pg_isready -U flow"]
interval: 10s
timeout: 5s
retries: 5
@@ -338,20 +338,20 @@ jobs:
langflow_postgres_data:
EOF
- name: Start stable Langflow with Docker Compose
- name: Start stable Hanzo Flow with Docker Compose
working-directory: docker-migration-test
run: |
echo "Starting Langflow stable version..."
echo "Starting Hanzo Flow stable version..."
docker compose up -d
echo "Waiting for Langflow to be healthy..."
timeout 180 bash -c 'until docker compose exec -T langflow curl -f http://localhost:7860/health_check 2>/dev/null; do sleep 5; done' || {
echo "Langflow stable failed to start"
echo "Waiting for Hanzo Flow to be healthy..."
timeout 180 bash -c 'until docker compose exec -T flow curl -f http://localhost:7860/health_check 2>/dev/null; do sleep 5; done' || {
echo "Hanzo Flow stable failed to start"
docker compose logs
exit 1
}
echo "Langflow stable is running"
echo "Hanzo Flow stable is running"
- name: Create witness flow via API
working-directory: docker-migration-test
@@ -394,43 +394,43 @@ jobs:
fi
echo "✅ Witness credential created successfully"
- name: Stop stable Langflow (keep PostgreSQL volume)
- name: Stop stable Hanzo Flow (keep PostgreSQL volume)
working-directory: docker-migration-test
run: |
echo "Stopping Langflow stable..."
docker compose stop langflow
docker compose rm -f langflow
echo "Stopping Hanzo Flow stable..."
docker compose stop flow
docker compose rm -f flow
- name: Update to nightly image
working-directory: docker-migration-test
run: |
NIGHTLY_TAG="${{ inputs.nightly_tag || 'langflowai/langflow-nightly:latest' }}"
NIGHTLY_TAG="${{ inputs.nightly_tag || 'langflowai/flow-nightly:latest' }}"
# Strip 'v' prefix from version part — Docker images are published without it
# e.g. langflowai/langflow-nightly:v1.10.0.dev20260522 → langflowai/langflow-nightly:1.10.0.dev20260522
# e.g. langflowai/flow-nightly:v1.10.0.dev20260522 → langflowai/flow-nightly:1.10.0.dev20260522
VERSION_PART="${NIGHTLY_TAG##*:}"
IMAGE_NAME="${NIGHTLY_TAG%%:*}"
DOCKER_TAG="${IMAGE_NAME}:${VERSION_PART#v}"
echo "Updating to nightly: $DOCKER_TAG"
# Update docker-compose.yml to use nightly image
sed -i "s|image: langflowai/langflow:latest|image: $DOCKER_TAG|" docker-compose.yml
sed -i "s|image: langflowai/flow:latest|image: $DOCKER_TAG|" docker-compose.yml
cat docker-compose.yml
- name: Start nightly Langflow with same PostgreSQL volume
- name: Start nightly Hanzo Flow with same PostgreSQL volume
working-directory: docker-migration-test
run: |
echo "Starting Langflow nightly version..."
docker compose up -d langflow
echo "Starting Hanzo Flow nightly version..."
docker compose up -d flow
echo "Waiting for Langflow nightly to be healthy..."
timeout 180 bash -c 'until docker compose exec -T langflow curl -f http://localhost:7860/health_check 2>/dev/null; do sleep 5; done' || {
echo "Langflow nightly failed to start"
docker compose logs langflow
echo "Waiting for Hanzo Flow nightly to be healthy..."
timeout 180 bash -c 'until docker compose exec -T flow curl -f http://localhost:7860/health_check 2>/dev/null; do sleep 5; done' || {
echo "Hanzo Flow nightly failed to start"
docker compose logs flow
exit 1
}
echo "Langflow nightly started successfully"
echo "Hanzo Flow nightly started successfully"
- name: Verify witness data persisted
working-directory: docker-migration-test
+14 -14
View File
@@ -75,7 +75,7 @@ jobs:
id: draft_url
if: success()
run: |
echo "url=${{ vars.DOCS_DRAFT_BASE_URL }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/index.html" >> $GITHUB_OUTPUT
echo "url=${{ vars.DOCS_DRAFT_BASE_URL }}/flow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/index.html" >> $GITHUB_OUTPUT
- name: Install dependencies
run: cd docs && npm install
@@ -87,7 +87,7 @@ jobs:
cd docs
npm run build |& tee $GITHUB_WORKSPACE/build.log
env:
BASE_URL: /langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}
BASE_URL: /flow-drafts/${{ steps.extract_branch.outputs.draft_directory }}
FORCE_COLOR: 0 # Disable color output
SEGMENT_PUBLIC_WRITE_KEY: ${{ vars.DOCS_DRAFT_IBM_SEGMENT_PUBLIC_WRITE_KEY }}
@@ -183,8 +183,8 @@ jobs:
run: |
set -o pipefail
echo "Checking for new assets." |& tee -a $GITHUB_WORKSPACE/deploy.log
echo "aws s3 sync docs/build/assets/ s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/assets/ --size-only --dryrun --no-progress" | tee -a $GITHUB_WORKSPACE/deploy.log
aws s3 sync docs/build/assets/ "s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/assets/" --size-only --dryrun --no-progress | tee $GITHUB_WORKSPACE/assets.log
echo "aws s3 sync docs/build/assets/ s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/flow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/assets/ --size-only --dryrun --no-progress" | tee -a $GITHUB_WORKSPACE/deploy.log
aws s3 sync docs/build/assets/ "s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/flow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/assets/" --size-only --dryrun --no-progress | tee $GITHUB_WORKSPACE/assets.log
- name: Determine Standard or Full Publish
id: check_full_publish
@@ -203,9 +203,9 @@ jobs:
run: |
set -o pipefail
cd docs
mkdir langflow-drafts
mv build langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}
cd langflow-drafts
mkdir flow-drafts
mv build flow-drafts/${{ steps.extract_branch.outputs.draft_directory }}
cd flow-drafts
# Records the repository that originally triggered the build so we can post back
# comments upon clean up of a stale draft if it still has an open pull request.
@@ -224,26 +224,26 @@ jobs:
fi
echo "Deploying draft to S3." |& tee -a $GITHUB_WORKSPACE/deploy.log
echo "aws s3 sync . s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts ${s3_params[@]}" |& tee -a $GITHUB_WORKSPACE/deploy.log
aws s3 sync . "s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts" "${s3_params[@]}" |& tee -a $GITHUB_WORKSPACE/deploy.log
echo "aws s3 sync . s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/flow-drafts ${s3_params[@]}" |& tee -a $GITHUB_WORKSPACE/deploy.log
aws s3 sync . "s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/flow-drafts" "${s3_params[@]}" |& tee -a $GITHUB_WORKSPACE/deploy.log
# Update .github_source_repository file metadata to mark last modified time of the draft.
# This will allow us to later determine if a draft is stale and needs to be cleaned up.
echo "Marking last modified time of the draft." |& tee -a $GITHUB_WORKSPACE/deploy.log
echo "aws s3 cp --metadata '{\"touched\": \"now\"}' \
s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository" \
s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/flow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/flow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository" \
|& tee -a $GITHUB_WORKSPACE/deploy.log
aws s3 cp --metadata '{ "touched": "now" }' \
s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/flow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
s3://${{ vars.DOCS_DRAFT_S3_BUCKET_NAME }}/flow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/.github_source_repository \
|& tee -a $GITHUB_WORKSPACE/deploy.log
- name: Invalidate CloudFront Cache
if: success()
run: |
invalidation_batch="{ \"Paths\": { \"Quantity\": 1, \"Items\": [\"/langflow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/*\"] }, \"CallerReference\": \"langflow-docs-draft-files-$(date +%s)\" }"
invalidation_batch="{ \"Paths\": { \"Quantity\": 1, \"Items\": [\"/flow-drafts/${{ steps.extract_branch.outputs.draft_directory }}/*\"] }, \"CallerReference\": \"flow-docs-draft-files-$(date +%s)\" }"
echo $invalidation_batch | jq . |& tee -a "$GITHUB_WORKSPACE/deploy.log"
echo "Creating invalidation." |& tee -a "$GITHUB_WORKSPACE/deploy.log"
+16 -16
View File
@@ -78,7 +78,7 @@ jobs:
- name: Determine version
id: version
run: |
version=$(uv tree 2>/dev/null | grep '^langflow-base' | cut -d' ' -f2 | sed 's/^v//')
version=$(uv tree 2>/dev/null | grep '^flow-base' | cut -d' ' -f2 | sed 's/^v//')
echo "Base version from pyproject.toml: $version"
if [ ${{inputs.pre_release}} == "true" ]; then
@@ -124,7 +124,7 @@ jobs:
- name: Determine version
id: version
run: |
version=$(uv tree 2>/dev/null | grep -E '^langflow(-nightly)?[[:space:]]' | cut -d' ' -f2 | sed 's/^v//')
version=$(uv tree 2>/dev/null | grep -E '^flow(-nightly)?[[:space:]]' | cut -d' ' -f2 | sed 's/^v//')
echo "Main version from pyproject.toml: $version"
if [ ${{inputs.pre_release}} == "true" ]; then
@@ -155,10 +155,10 @@ jobs:
matrix:
include:
- arch: amd64
runner: [Langflow-runner]
runner: [Hanzo Flow-runner]
- arch: arm64
runner:
[self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
[self-hosted, linux, ARM64, flow-ai-arm64-40gb-ephemeral]
runs-on: ${{ matrix.runner }}
steps:
- name: Check out the code
@@ -226,10 +226,10 @@ jobs:
matrix:
include:
- arch: amd64
runner: [Langflow-runner]
runner: [Hanzo Flow-runner]
- arch: arm64
runner:
[self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
[self-hosted, linux, ARM64, flow-ai-arm64-40gb-ephemeral]
runs-on: ${{ matrix.runner }}
steps:
- name: Check out the code
@@ -297,10 +297,10 @@ jobs:
matrix:
include:
- arch: amd64
runner: [Langflow-runner]
runner: [Hanzo Flow-runner]
- arch: arm64
runner:
[self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
[self-hosted, linux, ARM64, flow-ai-arm64-40gb-ephemeral]
runs-on: ${{ matrix.runner }}
steps:
- name: Check out the code
@@ -372,10 +372,10 @@ jobs:
matrix:
include:
- arch: amd64
runner: [Langflow-runner]
runner: [Hanzo Flow-runner]
- arch: arm64
runner:
[self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
[self-hosted, linux, ARM64, flow-ai-arm64-40gb-ephemeral]
runs-on: ${{ matrix.runner }}
steps:
- name: Check out the code
@@ -443,10 +443,10 @@ jobs:
matrix:
include:
- arch: amd64
runner: [Langflow-runner]
runner: [Hanzo Flow-runner]
- arch: arm64
runner:
[self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
[self-hosted, linux, ARM64, flow-ai-arm64-40gb-ephemeral]
runs-on: ${{ matrix.runner }}
steps:
- name: Check out the code
@@ -514,10 +514,10 @@ jobs:
matrix:
include:
- arch: amd64
runner: [Langflow-runner]
runner: [Hanzo Flow-runner]
- arch: arm64
runner:
[self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
[self-hosted, linux, ARM64, flow-ai-arm64-40gb-ephemeral]
runs-on: ${{ matrix.runner }}
steps:
- name: Check out the code
@@ -602,9 +602,9 @@ jobs:
id: version
run: |
if [[ "${{ inputs.release_type }}" == "base" ]]; then
version=$(uv tree 2>/dev/null | grep 'langflow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
version=$(uv tree 2>/dev/null | grep 'flow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
else
version=$(uv tree 2>/dev/null | grep -E '^langflow(-nightly)?[[:space:]]' | cut -d' ' -f2 | sed 's/^v//')
version=$(uv tree 2>/dev/null | grep -E '^flow(-nightly)?[[:space:]]' | cut -d' ' -f2 | sed 's/^v//')
fi
echo "Using version: $version"
echo version=$version >> $GITHUB_OUTPUT
+5 -5
View File
@@ -139,7 +139,7 @@ jobs:
if: ${{ inputs.base_version == '' && (inputs.release_type == 'base' || inputs.release_type == 'nightly-base') }}
id: get-version-base
run: |
version=$(uv tree | grep 'langflow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
version=$(uv tree | grep 'flow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
if [ -z "$version" ]; then
echo "Failed to extract version from uv tree output"
exit 1
@@ -150,7 +150,7 @@ jobs:
if: ${{ inputs.main_version == '' && (inputs.release_type == 'main' || inputs.release_type == 'main-ep' || inputs.release_type == 'nightly-main' || inputs.release_type == 'main-all' || inputs.release_type == 'nightly-main-all') }}
id: get-version-main
run: |
version=$(uv tree | grep -E '^langflow(-nightly)?[[:space:]]' | awk '{print $2}' | sed 's/^v//')
version=$(uv tree | grep -E '^flow(-nightly)?[[:space:]]' | awk '{print $2}' | sed 's/^v//')
echo version=$version
echo version=$version >> $GITHUB_OUTPUT
setup:
@@ -201,7 +201,7 @@ jobs:
fi
fi
build:
runs-on: [self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
runs-on: [self-hosted, linux, ARM64, flow-ai-arm64-40gb-ephemeral]
needs: [get-version, setup]
steps:
- name: Check out the code at a specific ref
@@ -288,7 +288,7 @@ jobs:
build_components:
if: ${{ inputs.release_type == 'main' }}
runs-on: [self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
runs-on: [self-hosted, linux, ARM64, flow-ai-arm64-40gb-ephemeral]
permissions:
packages: write
needs: [build, get-version]
@@ -398,4 +398,4 @@ jobs:
- name: Restart HuggingFace Spaces Build
run: |
uv run ./scripts/factory_restart_space.py --space "Langflow/Langflow" --token ${{ secrets.HUGGINGFACE_API_TOKEN }}
uv run ./scripts/factory_restart_space.py --space "Hanzo Flow/Hanzo Flow" --token ${{ secrets.HUGGINGFACE_API_TOKEN }}
+11 -11
View File
@@ -49,10 +49,10 @@ jobs:
matrix:
include:
- arch: amd64
runner: [Langflow-runner]
runner: [Hanzo Flow-runner]
- arch: arm64
runner:
[self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
[self-hosted, linux, ARM64, flow-ai-arm64-40gb-ephemeral]
runs-on: ${{ matrix.runner }}
steps:
- name: Check out the code
@@ -72,7 +72,7 @@ jobs:
id: version
run: |
echo "Extracting base version from pyproject.toml"
version=$(uv tree 2>/dev/null | grep 'langflow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
version=$(uv tree 2>/dev/null | grep 'flow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
# Verify nightly tag format
@@ -145,10 +145,10 @@ jobs:
matrix:
include:
- arch: amd64
runner: [Langflow-runner]
runner: [Hanzo Flow-runner]
- arch: arm64
runner:
[self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
[self-hosted, linux, ARM64, flow-ai-arm64-40gb-ephemeral]
runs-on: ${{ matrix.runner }}
steps:
- name: Check out the code
@@ -168,7 +168,7 @@ jobs:
id: version
run: |
echo "Extracting main version from pyproject.toml"
version=$(uv tree 2>/dev/null | grep -E '^langflow(-nightly)?[[:space:]]' | cut -d' ' -f2 | sed 's/^v//')
version=$(uv tree 2>/dev/null | grep -E '^flow(-nightly)?[[:space:]]' | cut -d' ' -f2 | sed 's/^v//')
# Verify nightly tag format
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.dev[0-9]+$ ]]; then
@@ -240,10 +240,10 @@ jobs:
matrix:
include:
- arch: amd64
runner: [Langflow-runner]
runner: [Hanzo Flow-runner]
- arch: arm64
runner:
[self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
[self-hosted, linux, ARM64, flow-ai-arm64-40gb-ephemeral]
runs-on: ${{ matrix.runner }}
steps:
- name: Check out the code
@@ -263,7 +263,7 @@ jobs:
id: version
run: |
echo "Extracting main version from pyproject.toml"
version=$(uv tree 2>/dev/null | grep -E '^langflow(-nightly)?[[:space:]]' | cut -d' ' -f2 | sed 's/^v//')
version=$(uv tree 2>/dev/null | grep -E '^flow(-nightly)?[[:space:]]' | cut -d' ' -f2 | sed 's/^v//')
# Verify nightly tag format
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.dev[0-9]+$ ]]; then
@@ -351,9 +351,9 @@ jobs:
id: version
run: |
if [[ "${{ inputs.release_type }}" == "nightly-base" ]]; then
version=$(uv tree 2>/dev/null | grep 'langflow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
version=$(uv tree 2>/dev/null | grep 'flow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
else
version=$(uv tree 2>/dev/null | grep -E '^langflow(-nightly)?[[:space:]]' | cut -d' ' -f2 | sed 's/^v//')
version=$(uv tree 2>/dev/null | grep -E '^flow(-nightly)?[[:space:]]' | cut -d' ' -f2 | sed 's/^v//')
fi
echo "Using version: $version"
echo version=$version >> $GITHUB_OUTPUT
+1 -1
View File
@@ -14,7 +14,7 @@ env:
jobs:
test-docker:
runs-on: [self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral]
runs-on: [self-hosted, linux, ARM64, flow-ai-arm64-40gb-ephemeral]
name: Test docker images
steps:
- uses: actions/checkout@v6
+1 -1
View File
@@ -41,7 +41,7 @@ jobs:
run: uv sync
- name: Run Mypy
run: |
uv run mypy --namespace-packages -p "langflow"
uv run mypy --namespace-packages -p "flow"
env:
GITHUB_TOKEN: ${{ secrets.github_token }}
+12 -12
View File
@@ -3,9 +3,9 @@ name: Database Migration Validation
on:
pull_request:
paths:
- 'src/backend/base/langflow/alembic/**'
- 'src/backend/base/langflow/services/database/models/**'
- 'src/backend/base/langflow/services/database/service.py'
- 'src/backend/base/flow/alembic/**'
- 'src/backend/base/flow/services/database/models/**'
- 'src/backend/base/flow/services/database/service.py'
- 'src/backend/tests/unit/alembic/**'
- '.github/workflows/migration-validation.yml'
@@ -18,13 +18,13 @@ jobs:
postgres:
image: postgres:16
env:
POSTGRES_USER: langflow
POSTGRES_PASSWORD: langflow
POSTGRES_DB: langflow
POSTGRES_USER: flow
POSTGRES_PASSWORD: flow
POSTGRES_DB: flow
ports:
- 5432:5432
options: >-
--health-cmd="pg_isready -U langflow"
--health-cmd="pg_isready -U flow"
--health-interval=10s
--health-timeout=5s
--health-retries=5
@@ -50,7 +50,7 @@ jobs:
- name: Check model/migration consistency
env:
MIGRATION_VALIDATION_CI: "true"
LANGFLOW_TEST_DATABASE_URI: "postgresql://langflow:langflow@localhost:5432/langflow"
LANGFLOW_TEST_DATABASE_URI: "postgresql://flow:flow@localhost:5432/flow"
run: |
uv run pytest src/backend/tests/unit/alembic/test_migration_execution.py -x -v
@@ -73,7 +73,7 @@ jobs:
id: changed-files
run: |
set -euo pipefail
CHANGED_FILES=$(git diff --name-only origin/main...HEAD | grep -E 'src/backend/base/langflow/alembic/versions/.*\.py$' | grep -v 'test_migrations/' || echo "")
CHANGED_FILES=$(git diff --name-only origin/main...HEAD | grep -E 'src/backend/base/flow/alembic/versions/.*\.py$' | grep -v 'test_migrations/' || echo "")
if [ -z "$CHANGED_FILES" ]; then
echo "No migration files changed"
@@ -89,14 +89,14 @@ jobs:
env:
MIGRATION_FILES: ${{ steps.changed-files.outputs.files }}
run: |
python src/backend/base/langflow/alembic/migration_validator.py $MIGRATION_FILES
python src/backend/base/flow/alembic/migration_validator.py $MIGRATION_FILES
- name: Generate validation report
if: always() && steps.changed-files.outputs.files != ''
env:
MIGRATION_FILES: ${{ steps.changed-files.outputs.files }}
run: |
python src/backend/base/langflow/alembic/migration_validator.py \
python src/backend/base/flow/alembic/migration_validator.py \
--json $MIGRATION_FILES > validation-report.json 2> validation-stderr.txt || true
if [ ! -s validation-report.json ]; then
echo "::error::Validator produced no output. Stderr:"
@@ -153,7 +153,7 @@ jobs:
}
message += `### Resources\n`;
message += `- Review the [DB Migration Guide](./src/backend/base/langflow/alembic/DB-MIGRATION-GUIDE.MD)\n`;
message += `- Review the [DB Migration Guide](./src/backend/base/flow/alembic/DB-MIGRATION-GUIDE.MD)\n`;
message += `- Use \`python scripts/generate_migration.py --help\` to generate compliant migrations\n\n`;
message += `### Common Issues & Solutions\n`;
+14 -14
View File
@@ -10,7 +10,7 @@ on:
options:
- ubuntu-latest
- self-hosted
- '["self-hosted", "linux", "ARM64", "langflow-ai-arm64-40gb-ephemeral"]'
- '["self-hosted", "linux", "ARM64", "flow-ai-arm64-40gb-ephemeral"]'
default: ubuntu-latest
skip_frontend_tests:
description: "Skip frontend tests. Only do this for testing purposes."
@@ -87,7 +87,7 @@ jobs:
- name: Generate main nightly tag
id: generate_main_tag
run: |
# langflow-nightly pins langflow-base-nightly[complete]==<exact dev>, so both tags
# flow-nightly pins flow-base-nightly[complete]==<exact dev>, so both tags
# MUST be identical. Compute them in ONE invocation (single PyPI snapshot) so they
# cannot drift across separate calls.
# NOTE: This outputs the tag with the `v` prefix.
@@ -124,8 +124,8 @@ jobs:
run: |
# If the main tag does not exist in GH, we create the base tag from the existing codebase.
git config --global user.email "bot-nightly-builds@langflow.org"
git config --global user.name "Langflow Bot"
git config --global user.email "[email protected]"
git config --global user.name "Hanzo Flow Bot"
MAIN_TAG="${{ steps.generate_main_tag.outputs.main_tag }}"
BASE_TAG="${{ steps.generate_base_tag.outputs.base_tag }}"
@@ -151,7 +151,7 @@ jobs:
git commit -m "Update version and project name"
echo "Tagging main with $MAIN_TAG"
if ! git tag -a $MAIN_TAG -m "Langflow nightly $MAIN_TAG"; then
if ! git tag -a $MAIN_TAG -m "Hanzo Flow nightly $MAIN_TAG"; then
echo "Tag creation failed. Exiting the workflow."
exit 1
fi
@@ -173,7 +173,7 @@ jobs:
working-directory: src/backend/base
run: |
# If the main tag already exists, we need to retrieve the base version from the main tag codebase.
version=$(uv tree | grep 'langflow-base' | awk '{print $3}' | head -n 1)
version=$(uv tree | grep 'flow-base' | awk '{print $3}' | head -n 1)
echo "base_tag=$version" >> $GITHUB_OUTPUT
echo "base_tag=$version"
@@ -240,8 +240,8 @@ jobs:
- name: Commit and push hash history changes
run: |
echo "=== Configuring git ==="
git config --global user.email "bot-nightly-builds@langflow.org"
git config --global user.name "Langflow Bot"
git config --global user.email "[email protected]"
git config --global user.name "Hanzo Flow Bot"
echo "=== Checking for hash history changes ==="
# Check if there are changes to commit (handles if it's a new file for first run)
@@ -317,7 +317,7 @@ jobs:
release-nightly-build:
if: github.repository == 'hanzoai/flow' && always() && needs.frontend-tests.result != 'failure' && needs.backend-unit-tests.result != 'failure' && needs.build-hash-history.result != 'failure'
name: Run Nightly Langflow Build
name: Run Nightly Hanzo Flow Build
needs: [create-nightly-tag, frontend-tests, backend-unit-tests, build-hash-history]
uses: ./.github/workflows/release_nightly.yml
with:
@@ -336,13 +336,13 @@ jobs:
db-migration-validation:
name: Run DB Migration Validation
needs: [create-nightly-tag, release-nightly-build]
if: ${{ github.repository == 'langflow-ai/langflow' && always() && needs.release-nightly-build.result == 'success' }}
if: ${{ github.repository == 'hanzoai/flow' && always() && needs.release-nightly-build.result == 'success' }}
uses: ./.github/workflows/db-migration-validation.yml
with:
# Pass Docker image reference for docker-compose and version without 'v' prefix for pip
# release_tag format: v1.10.0.dev20260522
# We need: langflowai/langflow-nightly:1.10.0.dev20260522 for Docker
nightly_tag: langflowai/langflow-nightly:${{ needs.create-nightly-tag.outputs.release_tag }}
# We need: langflowai/flow-nightly:1.10.0.dev20260522 for Docker
nightly_tag: langflowai/flow-nightly:${{ needs.create-nightly-tag.outputs.release_tag }}
secrets: inherit
slack-notification:
@@ -422,8 +422,8 @@ jobs:
- name: Configure Git
run: |
git config --global user.email "bot-nightly-builds@langflow.org"
git config --global user.name "Langflow Bot"
git config --global user.email "[email protected]"
git config --global user.name "Hanzo Flow Bot"
- name: "Setup Environment"
uses: astral-sh/setup-uv@v6
+6 -6
View File
@@ -43,7 +43,7 @@ on:
options:
- ubuntu-latest
- self-hosted
- '["self-hosted", "linux", "ARM64", "langflow-ai-arm64-40gb-ephemeral"]'
- '["self-hosted", "linux", "ARM64", "flow-ai-arm64-40gb-ephemeral"]'
default: ubuntu-latest
env:
POETRY_VERSION: "1.8.2"
@@ -207,13 +207,13 @@ jobs:
- name: Check Version
id: check-version
# We need to print $3 because langflow-base is a dependency of langflow
# We need to print $3 because flow-base is a dependency of flow
# For langlow we'd use print $2
run: |
version=$(uv tree | grep 'langflow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
url="https://pypi.org/pypi/langflow-base/json"
version=$(uv tree | grep 'flow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
url="https://pypi.org/pypi/flow-base/json"
if [ ${{ inputs.nightly }} == true ]; then
url="https://pypi.org/pypi/langflow-base-nightly/json"
url="https://pypi.org/pypi/flow-base-nightly/json"
fi
last_released_version=$(curl -s $url | jq -r '.releases | keys | .[]' | sort -V | tail -n 1)
@@ -239,7 +239,7 @@ jobs:
if: steps.check-version.outputs.skipped == 'false'
run: |
source new-venv/bin/activate
python -m langflow run --host localhost --port 7860 --backend-only &
python -m flow run --host localhost --port 7860 --backend-only &
SERVER_PID=$!
# Wait for the server to start
timeout 120 bash -c 'until curl -f http://localhost:7860/api/v1/auto_login; do sleep 5; done' || (echo "Server did not start in time" && kill $SERVER_PID && exit 1)
+3 -3
View File
@@ -250,14 +250,14 @@ jobs:
with:
images: |
langflowai/lfx
ghcr.io/langflow-ai/lfx
ghcr.io/flow-ai/lfx
tags: |
type=raw,value=${{ github.event.inputs.version }}${{ matrix.variant == 'alpine' && '-alpine' || '' }}
type=raw,value=latest${{ matrix.variant == 'alpine' && '-alpine' || '' }},enable=${{ github.event.inputs.pre_release == 'false' }}
labels: |
org.opencontainers.image.title=LFX
org.opencontainers.image.description=Langflow Executor - CLI tool for running Langflow AI workflows
org.opencontainers.image.vendor=Langflow
org.opencontainers.image.description=Hanzo Flow Executor - CLI tool for running Hanzo Flow AI workflows
org.opencontainers.image.vendor=Hanzo Flow
org.opencontainers.image.version=${{ github.event.inputs.version }}
- name: Build and push Docker image
+53 -53
View File
@@ -1,5 +1,5 @@
name: Langflow Release
run-name: Langflow Release by @${{ github.actor }}
name: Hanzo Flow Release
run-name: Hanzo Flow Release by @${{ github.actor }}
on:
workflow_dispatch:
@@ -9,12 +9,12 @@ on:
required: true
type: string
release_package_base:
description: "Release Langflow Base"
description: "Release Hanzo Flow Base"
required: true
type: boolean
default: false
release_package_main:
description: "Release Langflow"
description: "Release Hanzo Flow"
required: true
type: boolean
default: false
@@ -24,7 +24,7 @@ on:
type: boolean
default: false
release_sdk:
description: "Release langflow-sdk package (required when releasing LFX)"
description: "Release flow-sdk package (required when releasing LFX)"
required: false
type: boolean
default: false
@@ -34,12 +34,12 @@ on:
type: boolean
default: false
build_docker_base:
description: "Build Docker Image for Langflow Base"
description: "Build Docker Image for Hanzo Flow Base"
required: true
type: boolean
default: false
build_docker_main:
description: "Build Docker Image for Langflow"
description: "Build Docker Image for Hanzo Flow"
required: true
type: boolean
default: false
@@ -158,20 +158,20 @@ jobs:
- name: Validate that build-base is enabled if build-main is enabled
run: |
if [ "${{ inputs.release_package_main }}" = "true" ] && [ "${{ inputs.release_package_base }}" = "false" ]; then
echo "Error: Cannot release Langflow Main without releasing Langflow Base."
echo "Error: Cannot release Hanzo Flow Main without releasing Hanzo Flow Base."
echo "Please enable 'release_package_base' or disable 'release_package_main'."
exit 1
fi
if [ "${{ inputs.release_lfx }}" = "true" ] && [ "${{ inputs.release_sdk }}" = "false" ]; then
echo "Error: Cannot release LFX without releasing langflow-sdk."
echo "LFX depends on langflow-sdk. Please enable 'release_sdk' or disable 'release_lfx'."
echo "Error: Cannot release LFX without releasing flow-sdk."
echo "LFX depends on flow-sdk. Please enable 'release_sdk' or disable 'release_lfx'."
exit 1
fi
if [ "${{ inputs.release_package_main }}" = "true" ] && [ "${{ inputs.release_bundles }}" = "false" ]; then
echo "Error: Cannot release Langflow Main without releasing bundles."
echo "Langflow Main pins exact bundle versions (lfx-arxiv, lfx-duckduckgo, ...). Please enable 'release_bundles' or disable 'release_package_main'."
echo "Error: Cannot release Hanzo Flow Main without releasing bundles."
echo "Hanzo Flow Main pins exact bundle versions (lfx-arxiv, lfx-duckduckgo, ...). Please enable 'release_bundles' or disable 'release_package_main'."
exit 1
fi
@@ -212,12 +212,12 @@ jobs:
echo "Base version from pyproject.toml: $version"
if [ ${{inputs.pre_release}} == "true" ]; then
last_released_version=$(curl -s "https://pypi.org/pypi/langflow-base/json" | jq -r '.releases | keys | .[]' | grep -E '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
last_released_version=$(curl -s "https://pypi.org/pypi/flow-base/json" | jq -r '.releases | keys | .[]' | grep -E '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
version="$(uv run ./scripts/ci/langflow_pre_release_tag.py "$version" "$last_released_version")"
echo "Latest base pre-release version: $last_released_version"
echo "Base pre-release version to be released: $version"
else
last_released_version=$(curl -s "https://pypi.org/pypi/langflow-base/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
last_released_version=$(curl -s "https://pypi.org/pypi/flow-base/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
echo "Latest base release version: $last_released_version"
fi
@@ -257,16 +257,16 @@ jobs:
- name: Determine version
id: version
run: |
version=$(uv tree | grep -E '^langflow(-nightly)?[[:space:]]' | awk '{print $2}' | sed 's/^v//')
version=$(uv tree | grep -E '^flow(-nightly)?[[:space:]]' | awk '{print $2}' | sed 's/^v//')
echo "Main version from pyproject.toml: $version"
if [ ${{inputs.pre_release}} == "true" ]; then
last_released_version=$(curl -s "https://pypi.org/pypi/langflow/json" | jq -r '.releases | keys | .[]' | grep -E '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
last_released_version=$(curl -s "https://pypi.org/pypi/flow/json" | jq -r '.releases | keys | .[]' | grep -E '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
version="$(uv run ./scripts/ci/langflow_pre_release_tag.py "$version" "$last_released_version")"
echo "Latest main pre-release version: $last_released_version"
echo "Main pre-release version to be released: $version"
else
last_released_version=$(curl -s "https://pypi.org/pypi/langflow/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
last_released_version=$(curl -s "https://pypi.org/pypi/flow/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
echo "Latest main release version: $last_released_version"
fi
@@ -351,7 +351,7 @@ jobs:
prune-cache: false
- name: Install SDK dependencies
run: uv sync --dev --package langflow-sdk
run: uv sync --dev --package flow-sdk
- name: Determine version
id: version
@@ -363,19 +363,19 @@ jobs:
")
echo "SDK version from pyproject.toml: $version"
# Check if langflow-sdk exists on PyPI (may be first release)
pypi_response=$(curl -s -o /dev/null -w "%{http_code}" "https://pypi.org/pypi/langflow-sdk/json")
# Check if flow-sdk exists on PyPI (may be first release)
pypi_response=$(curl -s -o /dev/null -w "%{http_code}" "https://pypi.org/pypi/flow-sdk/json")
if [ "$pypi_response" = "404" ]; then
echo "langflow-sdk has never been published to PyPI. This will be the first release."
echo "flow-sdk has never been published to PyPI. This will be the first release."
last_released_version=""
else
if [ ${{inputs.pre_release}} == "true" ]; then
last_released_version=$(curl -s "https://pypi.org/pypi/langflow-sdk/json" | jq -r '.releases | keys | .[]' | grep -E '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
last_released_version=$(curl -s "https://pypi.org/pypi/flow-sdk/json" | jq -r '.releases | keys | .[]' | grep -E '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
version="$(uv run ./scripts/ci/langflow_pre_release_tag.py "$version" "$last_released_version")"
echo "Latest SDK pre-release version: $last_released_version"
echo "SDK pre-release version to be released: $version"
else
last_released_version=$(curl -s "https://pypi.org/pypi/langflow-sdk/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
last_released_version=$(curl -s "https://pypi.org/pypi/flow-sdk/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
echo "Latest SDK release version: $last_released_version"
fi
fi
@@ -403,7 +403,7 @@ jobs:
secrets: inherit
build-sdk:
name: Build langflow-sdk
name: Build flow-sdk
needs: [determine-sdk-version]
if: ${{ needs.determine-sdk-version.outputs.skipped == 'false' }}
runs-on: ubuntu-latest
@@ -460,7 +460,7 @@ jobs:
# importlib.metadata returns the PEP 440 canonical form, so normalize
# the expected version the same way the wheel filename check does.
NORMALIZED_VERSION=$(echo "$EXPECTED_VERSION" | sed 's/\.rc/rc/g; s/\.a/a/g; s/\.b/b/g; s/\.dev/dev/g')
./test-env/bin/python -c "from importlib.metadata import version; import langflow_sdk; installed_version = version('langflow-sdk'); print(f'langflow-sdk {installed_version} imported successfully'); assert installed_version == '$NORMALIZED_VERSION', f'Installed version {installed_version} does not match expected version $NORMALIZED_VERSION'"
./test-env/bin/python -c "from importlib.metadata import version; import langflow_sdk; installed_version = version('flow-sdk'); print(f'flow-sdk {installed_version} imported successfully'); assert installed_version == '$NORMALIZED_VERSION', f'Installed version {installed_version} does not match expected version $NORMALIZED_VERSION'"
- name: Upload Artifact
uses: actions/upload-artifact@v6
with:
@@ -509,31 +509,31 @@ jobs:
# Verify the change
echo "Updated pyproject.toml version:"
grep "^version" pyproject.toml
- name: Update langflow-sdk dependency for pre-release
- name: Update flow-sdk dependency for pre-release
if: ${{ inputs.pre_release && needs.build-sdk.result == 'success' }}
run: |
SDK_VERSION="${{ needs.determine-sdk-version.outputs.version }}"
echo "Updating langflow-sdk dependency to allow pre-release version: $SDK_VERSION"
echo "Updating flow-sdk dependency to allow pre-release version: $SDK_VERSION"
cd src/lfx
# Extract current langflow-sdk constraint from pyproject.toml
CURRENT_CONSTRAINT=$(grep -E '^\s*"langflow-sdk' pyproject.toml | head -1)
# Extract current flow-sdk constraint from pyproject.toml
CURRENT_CONSTRAINT=$(grep -E '^\s*"flow-sdk' pyproject.toml | head -1)
echo "Current constraint: $CURRENT_CONSTRAINT"
# Create new constraint using the next major derived from SDK_VERSION
SDK_BASE_VERSION=$(echo "$SDK_VERSION" | sed 's/[^0-9.].*$//')
SDK_MAJOR=$(echo "$SDK_BASE_VERSION" | cut -d. -f1)
NEXT_MAJOR=$((SDK_MAJOR + 1))
NEW_CONSTRAINT="\"langflow-sdk>=$SDK_VERSION,<$NEXT_MAJOR.dev0\""
NEW_CONSTRAINT="\"flow-sdk>=$SDK_VERSION,<$NEXT_MAJOR.dev0\""
echo "New constraint: $NEW_CONSTRAINT"
# Replace the constraint
sed -i.bak "s|\"langflow-sdk[^\"]*\"|$NEW_CONSTRAINT|" pyproject.toml
sed -i.bak "s|\"flow-sdk[^\"]*\"|$NEW_CONSTRAINT|" pyproject.toml
# Verify the change
echo "Updated langflow-sdk dependency:"
grep "langflow-sdk" pyproject.toml
echo "Updated flow-sdk dependency:"
grep "flow-sdk" pyproject.toml
- name: Build project for distribution
run: |
cd src/lfx
@@ -576,7 +576,7 @@ jobs:
path: src/lfx/dist
build-base:
name: Build Langflow Base
name: Build Hanzo Flow Base
needs: [build-lfx, build-sdk, determine-base-version, determine-lfx-version]
if: |
always() &&
@@ -686,7 +686,7 @@ jobs:
mkdir src/backend/base/dist
mv dist/*.whl src/backend/base/dist
uv pip install src/backend/base/dist/*.whl
uv run python -m langflow run --host localhost --port 7860 --backend-only &
uv run python -m flow run --host localhost --port 7860 --backend-only &
SERVER_PID=$!
# Wait for the server to start
timeout 120 bash -c 'until curl -f http://localhost:7860/api/v1/auto_login; do sleep 2; done' || (echo "Server did not start in time" && kill $SERVER_PID && exit 1)
@@ -710,7 +710,7 @@ jobs:
path: src/backend/base/dist
build-main:
name: Build Langflow Main
name: Build Hanzo Flow Main
needs:
[
build-base,
@@ -782,14 +782,14 @@ jobs:
# Verify the change
echo "Updated pyproject.toml version:"
grep "^version" pyproject.toml
- name: Update langflow-base dependency for pre-release
- name: Update flow-base dependency for pre-release
if: ${{ inputs.pre_release }}
run: |
BASE_VERSION="${{ needs.determine-base-version.outputs.version }}"
echo "Base version for pre-release: $BASE_VERSION"
# Extract current langflow-base constraint from pyproject.toml
CURRENT_CONSTRAINT=$(grep -E '^\s*"langflow-base' pyproject.toml | head -1)
# Extract current flow-base constraint from pyproject.toml
CURRENT_CONSTRAINT=$(grep -E '^\s*"flow-base' pyproject.toml | head -1)
echo "Current constraint: $CURRENT_CONSTRAINT"
# Extract the major.minor version (e.g., "0.8" from "~=0.8.0")
@@ -797,16 +797,16 @@ jobs:
NEXT_MAJOR=$((${MAJOR_MINOR%.*} + 1))
# Create new constraint: >=BASE_VERSION,<NEXT_MAJOR.dev0
NEW_CONSTRAINT="\"langflow-base>=$BASE_VERSION,<$NEXT_MAJOR.dev0\""
NEW_CONSTRAINT="\"flow-base>=$BASE_VERSION,<$NEXT_MAJOR.dev0\""
echo "New constraint: $NEW_CONSTRAINT"
# Replace the constraint
sed -i.bak "s|\"langflow-base[^\"]*\"|$NEW_CONSTRAINT|" pyproject.toml
sed -i.bak "s|\"flow-base[^\"]*\"|$NEW_CONSTRAINT|" pyproject.toml
# Verify the change
echo "Updated dependency:"
grep "langflow-base" pyproject.toml
grep "flow-base" pyproject.toml
- name: Build project for pre-release distribution
if: ${{ inputs.pre_release }}
run: make build pre=true args="--no-sources --wheel"
@@ -833,7 +833,7 @@ jobs:
- name: Test CLI
run: |
uv pip install dist/*.whl
uv run python -m langflow run --host localhost --port 7860 --backend-only &
uv run python -m flow run --host localhost --port 7860 --backend-only &
SERVER_PID=$!
# Wait for the server to start
timeout 120 bash -c 'until curl -f http://localhost:7860/health_check; do sleep 2; done' || (echo "Server did not start in time" && kill $SERVER_PID && exit 1)
@@ -857,7 +857,7 @@ jobs:
path: dist
build-bundles:
name: Build Langflow Bundles
name: Build Hanzo Flow Bundles
needs: [build-lfx, determine-lfx-version]
if: |
always() &&
@@ -924,7 +924,7 @@ jobs:
lfx-artifact-name: "dist-lfx"
publish-base:
name: Publish Langflow Base to PyPI
name: Publish Hanzo Flow Base to PyPI
if: ${{ inputs.release_package_base }}
needs: [build-base, test-cross-platform]
runs-on: ubuntu-latest
@@ -987,7 +987,7 @@ jobs:
done
publish-main:
name: Publish Langflow Main to PyPI
name: Publish Hanzo Flow Main to PyPI
if: ${{ inputs.release_package_main }}
needs: [build-main, test-cross-platform, publish-base]
runs-on: ubuntu-latest
@@ -1010,7 +1010,7 @@ jobs:
uv publish dist/*.whl
publish-sdk:
name: Publish langflow-sdk to PyPI
name: Publish flow-sdk to PyPI
needs: [build-sdk, test-cross-platform, ci]
if: |
always() &&
@@ -1066,7 +1066,7 @@ jobs:
cd src/lfx && uv publish dist/*.whl
call_docker_build_base:
name: Call Docker Build Workflow for Langflow Base
name: Call Docker Build Workflow for Hanzo Flow Base
if: ${{ inputs.build_docker_base }}
needs: [ci]
uses: ./.github/workflows/docker-build-v2.yml
@@ -1078,7 +1078,7 @@ jobs:
secrets: inherit
call_docker_build_main:
name: Call Docker Build Workflow for Langflow
name: Call Docker Build Workflow for Hanzo Flow
if: ${{ inputs.build_docker_main }}
needs: [ci]
uses: ./.github/workflows/docker-build-v2.yml
@@ -1090,7 +1090,7 @@ jobs:
secrets: inherit
call_docker_build_main_backend:
name: Call Docker Build Workflow for Langflow Backend
name: Call Docker Build Workflow for Hanzo Flow Backend
if: ${{ inputs.build_docker_main && !inputs.dry_run }}
needs: [call_docker_build_main]
uses: ./.github/workflows/docker-build-v2.yml
@@ -1102,7 +1102,7 @@ jobs:
secrets: inherit
call_docker_build_main_frontend:
name: Call Docker Build Workflow for Langflow Frontend
name: Call Docker Build Workflow for Hanzo Flow Frontend
if: ${{ inputs.build_docker_main && !inputs.dry_run }}
needs: [call_docker_build_main]
uses: ./.github/workflows/docker-build-v2.yml
@@ -1114,7 +1114,7 @@ jobs:
secrets: inherit
call_docker_build_main_ep:
name: Call Docker Build Workflow for Langflow with Entrypoint
name: Call Docker Build Workflow for Hanzo Flow with Entrypoint
if: ${{ inputs.build_docker_main }}
needs: [ci]
uses: ./.github/workflows/docker-build-v2.yml
@@ -1126,7 +1126,7 @@ jobs:
secrets: inherit
call_docker_build_main_all:
name: Call Docker Build Workflow for langflow-all
name: Call Docker Build Workflow for flow-all
if: ${{ inputs.build_docker_main }}
needs: [ci]
uses: ./.github/workflows/docker-build-v2.yml
+1 -1
View File
@@ -25,7 +25,7 @@ env:
jobs:
build-bundles:
name: Build Langflow Bundles
name: Build Hanzo Flow Bundles
runs-on: ubuntu-latest
defaults:
run:
+38 -38
View File
@@ -1,21 +1,21 @@
name: Langflow Nightly Build
run-name: Langflow Nightly Release by @${{ github.actor }}
name: Hanzo Flow Nightly Build
run-name: Hanzo Flow Nightly Release by @${{ github.actor }}
on:
workflow_call:
inputs:
build_docker_base:
description: "Build Docker Image for Langflow Nightly Base"
description: "Build Docker Image for Hanzo Flow Nightly Base"
required: true
type: boolean
default: false
build_docker_main:
description: "Build Docker Image for Langflow Nightly"
description: "Build Docker Image for Hanzo Flow Nightly"
required: true
type: boolean
default: false
build_docker_ep:
description: "Build Docker Image for Langflow Nightly with Entrypoint"
description: "Build Docker Image for Hanzo Flow Nightly with Entrypoint"
required: false
type: boolean
default: false
@@ -81,8 +81,8 @@ jobs:
run: |
name=$(grep '^name = "' src/sdk/pyproject.toml | head -n 1 | sed 's/.*"\(.*\)".*/\1/')
version=$(grep '^version = "' src/sdk/pyproject.toml | head -n 1 | sed 's/.*"\(.*\)".*/\1/')
if [ "$name" != "langflow-sdk-nightly" ]; then
echo "Name $name does not match langflow-sdk-nightly. Exiting the workflow."
if [ "$name" != "flow-sdk-nightly" ]; then
echo "Name $name does not match flow-sdk-nightly. Exiting the workflow."
exit 1
fi
if [ "v$version" != "${{ inputs.nightly_tag_sdk }}" ]; then
@@ -108,7 +108,7 @@ jobs:
version=$(echo $version | sed 's/^v//')
echo "version=$version" >> $GITHUB_OUTPUT
- name: Build langflow-sdk for distribution
- name: Build flow-sdk for distribution
run: |
make sdk_build args="--wheel"
@@ -130,7 +130,7 @@ jobs:
# PyPI publishing moved to after cross-platform testing
- name: Upload langflow-sdk Artifact
- name: Upload flow-sdk Artifact
uses: actions/upload-artifact@v6
with:
name: dist-nightly-sdk
@@ -143,7 +143,7 @@ jobs:
path: src/lfx/dist
build-nightly-base:
name: Build Langflow Nightly Base
name: Build Hanzo Flow Nightly Base
needs: [build-nightly-lfx]
if: ${{ always() && (needs.build-nightly-lfx.result == 'success' || inputs.build_lfx == false) }}
runs-on: ubuntu-latest
@@ -188,12 +188,12 @@ jobs:
- name: Verify Nightly Name and Version
id: verify
run: |
name=$(uv tree | grep 'langflow-base' | awk '{print $2}' | head -n 1)
version=$(uv tree | grep 'langflow-base' | awk '{print $3}' | head -n 1)
# Strip extras from package name (e.g., "langflow-base-nightly[complete]" -> "langflow-base-nightly")
name=$(uv tree | grep 'flow-base' | awk '{print $2}' | head -n 1)
version=$(uv tree | grep 'flow-base' | awk '{print $3}' | head -n 1)
# Strip extras from package name (e.g., "flow-base-nightly[complete]" -> "flow-base-nightly")
name_without_extras=$(echo $name | sed 's/\[.*\]//')
if [ "$name_without_extras" != "langflow-base-nightly" ]; then
echo "Name $name_without_extras does not match langflow-base-nightly. Exiting the workflow."
if [ "$name_without_extras" != "flow-base-nightly" ]; then
echo "Name $name_without_extras does not match flow-base-nightly. Exiting the workflow."
echo "skipped=true" >> $GITHUB_OUTPUT
exit 1
fi
@@ -207,13 +207,13 @@ jobs:
echo "version=$version" >> $GITHUB_OUTPUT
echo "skipped=false" >> $GITHUB_OUTPUT
- name: Build Langflow Base for distribution
- name: Build Hanzo Flow Base for distribution
run: |
rm -rf src/backend/base/dist
rm -rf dist
make build base=true args="--no-sources --wheel"
- name: Test Langflow Base CLI
- name: Test Hanzo Flow Base CLI
run: |
# TODO: Unsure why the whl is not built in src/backend/base/dist
mkdir src/backend/base/dist
@@ -221,7 +221,7 @@ jobs:
# Install with [complete] extra to test all optional dependencies
WHEEL_FILE=$(ls src/backend/base/dist/*.whl)
uv pip install "${WHEEL_FILE}[complete]"
uv run python -m langflow run --host localhost --port 7860 --backend-only &
uv run python -m flow run --host localhost --port 7860 --backend-only &
SERVER_PID=$!
# Wait for the server to start
timeout 120 bash -c 'until curl -f http://localhost:7860/api/v1/auto_login; do sleep 2; done' || (echo "Server did not start in time" && kill $SERVER_PID && exit 1)
@@ -245,7 +245,7 @@ jobs:
path: src/backend/base/dist
build-nightly-main:
name: Build Langflow Nightly Main
name: Build Hanzo Flow Nightly Main
needs: [build-nightly-base]
runs-on: ubuntu-latest
outputs:
@@ -291,16 +291,16 @@ jobs:
echo "Installing LFX from built wheel..."
uv pip install --force-reinstall --no-deps lfx-dist/*.whl
fi
echo "Installing langflow-base from built wheel..."
echo "Installing flow-base from built wheel..."
uv pip install --force-reinstall --no-deps base-dist/*.whl
- name: Verify Nightly Name and Version
id: verify
run: |
name=$(uv tree | grep -E '^langflow(-nightly)?[[:space:]]' | awk '{print $1}')
version=$(uv tree | grep -E '^langflow(-nightly)?[[:space:]]' | awk '{print $2}')
if [ "$name" != "langflow-nightly" ]; then
echo "Name $name does not match langflow-nightly. Exiting the workflow."
name=$(uv tree | grep -E '^flow(-nightly)?[[:space:]]' | awk '{print $1}')
version=$(uv tree | grep -E '^flow(-nightly)?[[:space:]]' | awk '{print $2}')
if [ "$name" != "flow-nightly" ]; then
echo "Name $name does not match flow-nightly. Exiting the workflow."
exit 1
fi
if [ "$version" != "${{ inputs.nightly_tag_main }}" ]; then
@@ -314,12 +314,12 @@ jobs:
if: needs.build-nightly-base.outputs.skipped == 'false'
run: sleep 300 # wait for 5 minutes to ensure PyPI propagation of base
- name: Build Langflow Main for distribution
- name: Build Hanzo Flow Main for distribution
run: make build main=true args="--no-sources --wheel"
- name: Test Langflow Main CLI
- name: Test Hanzo Flow Main CLI
run: |
uv pip install dist/*.whl
uv run python -m langflow run --host localhost --port 7860 --backend-only &
uv run python -m flow run --host localhost --port 7860 --backend-only &
SERVER_PID=$!
# Wait for the server to start
timeout 120 bash -c 'until curl -f http://localhost:7860/health_check; do sleep 2; done' || (echo "Server did not start in time" && kill $SERVER_PID && exit 1)
@@ -334,12 +334,12 @@ jobs:
echo "Server terminated successfully"
fi
- name: Prepare Langflow Main artifact
- name: Prepare Hanzo Flow Main artifact
run: |
shopt -s nullglob
MAIN_WHEELS=(dist/langflow_nightly-*.whl)
if [ ${#MAIN_WHEELS[@]} -ne 1 ]; then
echo "Expected exactly one langflow-nightly wheel in dist/, found ${#MAIN_WHEELS[@]}"
echo "Expected exactly one flow-nightly wheel in dist/, found ${#MAIN_WHEELS[@]}"
ls -la dist/
exit 1
fi
@@ -429,7 +429,7 @@ jobs:
with:
ref: ${{ inputs.nightly_tag_release }}
persist-credentials: true
- name: Download langflow-sdk artifact
- name: Download flow-sdk artifact
uses: actions/download-artifact@v8
with:
name: dist-nightly-sdk
@@ -447,7 +447,7 @@ jobs:
make sdk_publish
publish-nightly-base:
name: Publish Langflow Base Nightly to PyPI
name: Publish Hanzo Flow Base Nightly to PyPI
needs: [build-nightly-base, test-cross-platform, publish-nightly-lfx]
if: ${{ always() && needs.build-nightly-base.result == 'success' && needs.test-cross-platform.result == 'success' && (needs.publish-nightly-lfx.result == 'success' || inputs.build_lfx == false) }}
runs-on: ubuntu-latest
@@ -476,8 +476,8 @@ jobs:
make publish base=true
publish-nightly-bundles:
name: Publish Langflow Bundles Nightly to PyPI
# langflow-nightly pins each `lfx-<name>-nightly==<dev>` exactly, so the
name: Publish Hanzo Flow Bundles Nightly to PyPI
# flow-nightly pins each `lfx-<name>-nightly==<dev>` exactly, so the
# bundles must be on PyPI before main is published (publish-nightly-main
# gates on this job). They depend on `lfx-nightly`, so gate on the lfx
# publish too (or skip it when lfx isn't being rebuilt).
@@ -526,7 +526,7 @@ jobs:
fi
publish-nightly-main:
name: Publish Langflow Main Nightly to PyPI
name: Publish Hanzo Flow Main Nightly to PyPI
needs: [build-nightly-main, test-cross-platform, publish-nightly-base, publish-nightly-bundles]
if: ${{ always() && needs.build-nightly-main.result == 'success' && needs.test-cross-platform.result == 'success' && needs.publish-nightly-base.result == 'success' && needs.publish-nightly-bundles.result == 'success' }}
runs-on: ubuntu-latest
@@ -554,7 +554,7 @@ jobs:
make publish main=true
call_docker_build_base:
name: Call Docker Build Workflow for Langflow Base
name: Call Docker Build Workflow for Hanzo Flow Base
if: ${{ always() && inputs.build_docker_base }}
needs: [build-nightly-base, build-nightly-main]
uses: ./.github/workflows/docker-nightly-build.yml
@@ -565,7 +565,7 @@ jobs:
secrets: inherit
call_docker_build_main:
name: Call Docker Build Workflow for Langflow
name: Call Docker Build Workflow for Hanzo Flow
if: ${{ always() && inputs.build_docker_main }}
needs: [build-nightly-main, call_docker_build_base]
uses: ./.github/workflows/docker-nightly-build.yml
@@ -577,7 +577,7 @@ jobs:
# TODO: Uncomment this when our runner can fit the builds that contain pytorch (and other large dependencies)
# call_docker_build_main_all:
# name: Call Docker Build Workflow for langflow-all
# name: Call Docker Build Workflow for flow-all
# if: always() && ${{ inputs.build_docker_main == 'true' }}
# needs: [build-nightly-main]
# uses: ./.github/workflows/docker-nightly-build.yml
@@ -588,7 +588,7 @@ jobs:
# secrets: inherit
call_docker_build_main_ep:
name: Call Docker Build Workflow for Langflow with Entrypoint
name: Call Docker Build Workflow for Hanzo Flow with Entrypoint
if: ${{ always() && inputs.build_docker_ep }}
needs: [build-nightly-main, call_docker_build_main]
uses: ./.github/workflows/docker-build-v2.yml
+1 -1
View File
@@ -166,7 +166,7 @@ jobs:
Critical functionality validated:
- ${backendEmoji} **Backend**: 11 essential test files (database, auth, API endpoints, flows, components)
- ${lfxEmoji} **LFX**: Graph tests (langflow execution) - runs in isolation
- ${lfxEmoji} **LFX**: Graph tests (flow execution) - runs in isolation
- ${frontendEmoji} **Frontend**: Unit tests only (components, utilities)
**Coverage**: Core functionality without external dependencies
+2 -2
View File
@@ -3,9 +3,9 @@ name: Template Tests
on:
pull_request:
paths:
- 'src/backend/base/langflow/initial_setup/starter_projects/**'
- 'src/backend/base/flow/initial_setup/starter_projects/**'
- 'src/backend/tests/unit/template/test_starter_projects.py'
- 'src/backend/base/langflow/utils/template_validation.py'
- 'src/backend/base/flow/utils/template_validation.py'
- '.github/workflows/template-tests.yml'
workflow_dispatch:
+1 -1
View File
@@ -60,7 +60,7 @@ on:
options:
- ubuntu-latest
- self-hosted
- '["self-hosted", "linux", "ARM64", "langflow-ai-arm64-40gb-ephemeral"]'
- '["self-hosted", "linux", "ARM64", "flow-ai-arm64-40gb-ephemeral"]'
default: ubuntu-latest
env:
+3 -3
View File
@@ -250,7 +250,7 @@ dmypy.json
# Poetry
.testenv/*
langflow.db
flow.db
.githooks/prepare-commit-msg
@@ -260,8 +260,8 @@ langflow.db
.docusaurus/
/tmp/*
src/backend/langflow/frontend/
src/backend/base/langflow/frontend/
src/backend/flow/frontend/
src/backend/base/flow/frontend/
.docker
scratchpad*
chroma*/*
+2 -2
View File
@@ -29,7 +29,7 @@ repos:
exclude: ^docs/.*/API-Reference/python-examples/
- id: validate-migrations
name: Validate Alembic Migrations (Expand-Contract)
entry: python src/backend/base/langflow/alembic/migration_validator.py
entry: python src/backend/base/flow/alembic/migration_validator.py
language: python
files: (alembic|migrations)/versions/.*\.py$
additional_dependencies: [sqlalchemy, alembic]
@@ -69,7 +69,7 @@ repos:
name: Validate Starter Project Templates
entry: uv run python src/backend/tests/unit/template/test_starter_projects.py
language: system
files: ^src/backend/base/langflow/initial_setup/starter_projects/.*\.json$
files: ^src/backend/base/flow/initial_setup/starter_projects/.*\.json$
pass_filenames: false
args: [--security-check]
- id: check-deprecated-imports
+279 -279
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -44,7 +44,7 @@
"args": [
"run",
"--frontend-path",
"${workspaceFolder}/src/backend/base/langflow/frontend",
"${workspaceFolder}/src/backend/base/flow/frontend",
"--env-file",
"${workspaceFolder}/.env"
],
+2 -2
View File
@@ -1,4 +1,4 @@
# Langflow Development Guide (Example)
# Hanzo Flow Development Guide (Example)
> **This is an EXAMPLE file.** Use at your own risk.
> It is provided as a reference template for development standards and coding conventions.
@@ -487,6 +487,6 @@ npx vitest run tests/your_tests.test.ts --coverage
---
> **This guide applies to every line of code in the Langflow project.**
> **This guide applies to every line of code in the Hanzo Flow project.**
> **When in doubt, choose simplicity. When trade-offs arise, follow the priority order in Section 1.**
> **Build for correctness first. Optimize later. Test always.**
+10 -10
View File
@@ -4,25 +4,25 @@ Guidance for AI coding agents working in this repository.
> **Before you write code, read [docs/agents/PHILOSOPHY.md](./docs/agents/PHILOSOPHY.md).** Most off-narrative work comes from skipping it.
## What Langflow is
## What Hanzo Flow is
Langflow is a **visual flow builder first**. Users drag components onto a canvas, wire them together, and either run the resulting flow in the Playground, deploy it as an API, or expose it as an MCP server. Saved flows are persistent JSON artifacts running in production — backwards compatibility for components is non-negotiable.
Hanzo Flow is a **visual flow builder first**. Users drag components onto a canvas, wire them together, and either run the resulting flow in the Playground, deploy it as an API, or expose it as an MCP server. Saved flows are persistent JSON artifacts running in production — backwards compatibility for components is non-negotiable.
The repo is three Python packages and one frontend:
- **`lfx`** (`src/lfx/`): the executor core. Component base classes, the graph engine, and built-in components live here. Should not depend on `langflow` or `langflow-base` — see [docs/agents/ARCHITECTURE.md](./docs/agents/ARCHITECTURE.md) for the ~14 known violations to fix-not-extend.
- **`langflow-base`** (`src/backend/base/langflow/`): the platform. FastAPI routes, auth, persistence, alembic, services. May import `lfx`.
- **`langflow`**: the integration distribution that ships everything together.
- **`lfx`** (`src/lfx/`): the executor core. Component base classes, the graph engine, and built-in components live here. Should not depend on `flow` or `flow-base` — see [docs/agents/ARCHITECTURE.md](./docs/agents/ARCHITECTURE.md) for the ~14 known violations to fix-not-extend.
- **`flow-base`** (`src/backend/base/flow/`): the platform. FastAPI routes, auth, persistence, alembic, services. May import `lfx`.
- **`flow`**: the integration distribution that ships everything together.
- **`frontend`** (`src/frontend/`): React 19 + TypeScript + Vite + Zustand + `@xyflow/react`. Talks to the backend over HTTP/WebSocket only.
Dependencies flow one way: `frontend → langflow → langflow-base → lfx`. See [docs/agents/ARCHITECTURE.md](./docs/agents/ARCHITECTURE.md).
Dependencies flow one way: `frontend → flow → flow-base → lfx`. See [docs/agents/ARCHITECTURE.md](./docs/agents/ARCHITECTURE.md).
## Non-negotiable tenets
These are extracted from [PHILOSOPHY.md](./docs/agents/PHILOSOPHY.md). The full file has the rest; these are the ones every change must respect.
1. **Flows are user artifacts.** Component class names, `name` attributes, input/output names, and input types are frozen once shipped. Mark old components `legacy=True` instead of editing.
2. **Every backend feature must land on the canvas.** If it can't be a component or a property of one, it's an SDK feature and belongs in `lfx`, not `langflow-base`.
2. **Every backend feature must land on the canvas.** If it can't be a component or a property of one, it's an SDK feature and belongs in `lfx`, not `flow-base`.
3. **Components are the unit of work.** Don't add a route, store, or service unless a component or UI page consumes it.
4. **Visible data flow beats clever magic.** Pass data through inputs and outputs. No hidden globals or side-channel state.
5. **Composition over capability.** One job per component. Split before you add a tenth input.
@@ -55,7 +55,7 @@ Read the file that matches your task before you write code.
```bash
make init # Install all dependencies + pre-commit hooks
make run_cli # Build and run Langflow (http://localhost:7860)
make run_cli # Build and run Hanzo Flow (http://localhost:7860)
make run_clic # Clean build and run (use when frontend issues occur)
```
@@ -96,9 +96,9 @@ make tests_frontend # Playwright e2e tests
# lfx tests specifically — run uv sync inside src/lfx (not src/lfx/src/lfx)
cd src/lfx && uv sync && uv run pytest
# Sub-package tests (langflow-base, lfx) — sync that package's dev group first,
# Sub-package tests (flow-base, lfx) — sync that package's dev group first,
# otherwise dev-only deps like fakeredis stay uninstalled.
uv sync --group dev --package langflow-base
uv sync --group dev --package flow-base
```
See [docs/agents/TESTING.md](./docs/agents/TESTING.md) for fixtures, base classes, and the graph testing pattern.
+4 -4
View File
@@ -1,6 +1,6 @@
---
version: alpha
name: Langflow
name: Hanzo Flow
description: Visual AI workflow builder for composing LLM-powered applications
colors:
# Core UI palette
@@ -509,7 +509,7 @@ components:
## Overview
Langflow is a visual AI workflow builder where users compose LLM-powered applications by dragging, connecting, and configuring modular components on an infinite canvas. The design language is that of a professional developer tool -- clean, information-dense, and deliberately restrained. Color is earned, not decorative; every hue in the system carries semantic meaning.
Hanzo Flow is a visual AI workflow builder where users compose LLM-powered applications by dragging, connecting, and configuring modular components on an infinite canvas. The design language is that of a professional developer tool -- clean, information-dense, and deliberately restrained. Color is earned, not decorative; every hue in the system carries semantic meaning.
The aesthetic sits between a code editor and a node-based creative tool. The core UI is strictly monochromatic -- black primary on white, with a warm zinc-gray scale for layering. This neutral foundation lets the **data type color system** (14 distinct hues encoding connection compatibility) and **accent families** (emerald for success, indigo for selection, pink for components) communicate meaning without competing for attention. The result is an interface that feels focused and engineered: complexity emerges from the user's composition, not from the UI itself.
@@ -555,7 +555,7 @@ Used for build status indicators, connection health, and real-time feedback dots
### Data Type Color System
Langflow uses **14 distinct hues** to encode the type of data flowing through node connections. Each type has a saturated foreground and a light-tint background. In **light mode**, the base token is the saturated color (used for port dots and connection lines) and the `-foreground` token is the light tint (used for backgrounds). In **dark mode, these roles swap** -- the base becomes the light tint and the foreground becomes the saturated color. This ensures readability against both light and dark surfaces.
Hanzo Flow uses **14 distinct hues** to encode the type of data flowing through node connections. Each type has a saturated foreground and a light-tint background. In **light mode**, the base token is the saturated color (used for port dots and connection lines) and the `-foreground` token is the light tint (used for backgrounds). In **dark mode, these roles swap** -- the base becomes the light tint and the foreground becomes the saturated color. This ensures readability against both light and dark surfaces.
| Data Type | Color Name | Hex (saturated) | Used For |
|:----------|:-----------|:-----------------|:---------|
@@ -723,7 +723,7 @@ Rounded bordered containers with icon + text layout. Default variant uses standa
### Canvas Nodes
The core UI element of Langflow. Each node is a white rounded card on the canvas containing typed input/output ports, configuration fields, and a status indicator.
The core UI element of Hanzo Flow. Each node is a white rounded card on the canvas containing typed input/output ports, configuration fields, and a status indicator.
- **Port dots** use the data type color system to visually encode connection compatibility. When two ports share a compatible type, their colors match, providing immediate visual feedback.
- **Selected nodes** show an indigo ring (`node-selected: #4F46E5`) replacing the standard border.
+2 -2
View File
@@ -202,7 +202,7 @@ Navigate to http://localhost:3001/ in a browser and view the documentation. Docu
## Adding or Modifying a Component
Components reside in folders under `src/backend/base/langflow`, and their unit tests under `src/backend/base/tests/unit/components`.
Components reside in folders under `src/backend/base/flow`, and their unit tests under `src/backend/base/tests/unit/components`.
> [!IMPORTANT]
> **Component Development Mode**: When actively developing components, make sure to run the backend with `LFX_DEV=1` to enable live reloading:
@@ -272,7 +272,7 @@ You may observe some quirky things:
There are some files that change without you having made changes:
- Files in `src/backend/base/langflow/initial_setup/starter_projects` modify after `hanzoflow run`; these are formatting changes. Feel free to commit (or ignore) them.
- Files in `src/backend/base/flow/initial_setup/starter_projects` modify after `hanzoflow run`; these are formatting changes. Feel free to commit (or ignore) them.
- `uv.lock` and `src/frontend/package-lock.json` files can be modified by `make` targets; changes should not be committed by individual contributors.
- You can exclude these from consideration in git: `git update-index --assume-unchanged uv.lock src/frontend/package-lock.json`
- You can re-include these from consideration in git: `git update-index --no-assume-unchanged uv.lock src/frontend/package-lock.json`
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2024 Langflow (https://github.com/langflow-ai/langflow)
Copyright (c) 2024 Hanzo Flow (https://github.com/hanzoai/flow)
Copyright (c) 2024-2026 Hanzo AI, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
+6 -6
View File
@@ -3,7 +3,7 @@
## Overview
**Hanzo Flow** is a powerful platform for building and deploying AI-powered agents and workflows. It provides developers with both a visual authoring experience and built-in API and MCP servers.
**Upstream**: Langflow (MIT). Internal package name `flow`; canonical env prefix `FLOW_*` (legacy `LANGFLOW_*` retained only for backwards compatibility — do not introduce new `LANGFLOW_*` references).
**Upstream**: Hanzo Flow (MIT). Internal package name `flow`; canonical env prefix `FLOW_*` (legacy `LANGFLOW_*` retained only for backwards compatibility — do not introduce new `LANGFLOW_*` references).
## Tech Stack
- **Backend**: Python (FastAPI, SQLModel, Alembic)
@@ -23,21 +23,21 @@ Three Python packages in a uv workspace:
| Package | PyPI name | Dir | Purpose |
|---------|-----------|-----|---------|
| `flow` | `langflow-base` | `src/backend/base/flow/` | Main backend package (454 files) |
| `flow` | `flow-base` | `src/backend/base/flow/` | Main backend package (454 files) |
| `flow` (root) | `hanzoflow` | `src/backend/flow/` | Root package (version only) |
| `lfx` | `lfx` | `src/lfx/src/lfx/` | Lightweight executor, standalone CLI |
### Internal package name: `flow`
- All Python imports use `from flow.xxx` / `import flow.xxx`
- Entry point: `hanzo-flow = "flow.launcher:main"` (root pyproject.toml)
- Entry point: `langflow-base = "flow.launcher:main"` (base pyproject.toml)
- Entry point: `flow-base = "flow.launcher:main"` (base pyproject.toml)
- Hatch build target: `packages = ["flow"]` (base), `packages = ["src/backend/flow"]` (root)
- The `langflow` compat shim package has been removed (was at `src/backend/base/langflow/`)
- The `flow` compat shim package has been removed (was at `src/backend/base/flow/`)
- The `hanzoflow` package dir has been renamed to `flow`
### PyPI package names (unchanged)
- `hanzoflow` -- root package name in pyproject.toml
- `langflow-base` -- base package name in pyproject.toml
- `flow-base` -- base package name in pyproject.toml
- `lfx` -- executor package name
### Environment variables (backwards compat)
@@ -50,7 +50,7 @@ Three Python packages in a uv workspace:
## Key Files
- `pyproject.toml` -- Root project config (PyPI name: hanzoflow)
- `src/backend/base/pyproject.toml` -- Base package config (PyPI name: langflow-base)
- `src/backend/base/pyproject.toml` -- Base package config (PyPI name: flow-base)
- `src/backend/base/flow/launcher.py` -- Main entry point (was langflow_launcher.py)
- `src/backend/base/flow/__main__.py` -- CLI commands (typer app)
- `src/backend/base/flow/main.py` -- FastAPI app factory
+26 -26
View File
@@ -49,7 +49,7 @@ help: ## show basic help message with common commands
@echo ''
@echo "$(GREEN)Basic Commands:$(NC)"
@echo " $(GREEN)make init$(NC) - Initialize project (install all dependencies)"
@echo " $(GREEN)make run_cli$(NC) - Run Langflow CLI"
@echo " $(GREEN)make run_cli$(NC) - Run Hanzo Flow CLI"
@echo " $(GREEN)make run_clic$(NC) - Run CLI with fresh frontend build"
@echo " $(GREEN)make format$(NC) - Format all code (backend + frontend)"
@echo " $(GREEN)make tests$(NC) - Run all tests"
@@ -566,13 +566,13 @@ patch: ## Update version across all projects. Usage: make patch v=1.5.0
LANGFLOW_VERSION="$(v)"; \
LANGFLOW_BASE_VERSION=$$(echo "$$LANGFLOW_VERSION" | sed -E 's/^[0-9]+\.(.*)$$/0.\1/'); \
\
echo "$(GREEN)Langflow version: $$LANGFLOW_VERSION$(NC)"; \
echo "$(GREEN)Langflow-base version: $$LANGFLOW_BASE_VERSION$(NC)"; \
echo "$(GREEN)Hanzo Flow version: $$LANGFLOW_VERSION$(NC)"; \
echo "$(GREEN)Hanzo Flow-base version: $$LANGFLOW_BASE_VERSION$(NC)"; \
\
echo "$(GREEN)Updating main pyproject.toml...$(NC)"; \
python -c "import re; fname='pyproject.toml'; txt=open(fname).read(); txt=re.sub(r'^version = \".*\"', 'version = \"$$LANGFLOW_VERSION\"', txt, flags=re.MULTILINE); txt=re.sub(r'\"langflow-base==.*\"', '\"langflow-base==$$LANGFLOW_BASE_VERSION\"', txt); open(fname, 'w').write(txt)"; \
python -c "import re; fname='pyproject.toml'; txt=open(fname).read(); txt=re.sub(r'^version = \".*\"', 'version = \"$$LANGFLOW_VERSION\"', txt, flags=re.MULTILINE); txt=re.sub(r'\"flow-base==.*\"', '\"flow-base==$$LANGFLOW_BASE_VERSION\"', txt); open(fname, 'w').write(txt)"; \
\
echo "$(GREEN)Updating langflow-base pyproject.toml...$(NC)"; \
echo "$(GREEN)Updating flow-base pyproject.toml...$(NC)"; \
python -c "import re; fname='src/backend/base/pyproject.toml'; txt=open(fname).read(); txt=re.sub(r'^version = \".*\"', 'version = \"$$LANGFLOW_BASE_VERSION\"', txt, flags=re.MULTILINE); open(fname, 'w').write(txt)"; \
\
echo "$(GREEN)Updating frontend package.json...$(NC)"; \
@@ -580,8 +580,8 @@ patch: ## Update version across all projects. Usage: make patch v=1.5.0
\
echo "$(GREEN)Validating version changes...$(NC)"; \
if ! grep -q "^version = \"$$LANGFLOW_VERSION\"" pyproject.toml; then echo "$(RED)✗ Main pyproject.toml version validation failed$(NC)"; exit 1; fi; \
if ! grep -q "\"langflow-base==$$LANGFLOW_BASE_VERSION\"" pyproject.toml; then echo "$(RED)✗ Main pyproject.toml langflow-base dependency validation failed$(NC)"; exit 1; fi; \
if ! grep -q "^version = \"$$LANGFLOW_BASE_VERSION\"" src/backend/base/pyproject.toml; then echo "$(RED)✗ Langflow-base pyproject.toml version validation failed$(NC)"; exit 1; fi; \
if ! grep -q "\"flow-base==$$LANGFLOW_BASE_VERSION\"" pyproject.toml; then echo "$(RED)✗ Main pyproject.toml flow-base dependency validation failed$(NC)"; exit 1; fi; \
if ! grep -q "^version = \"$$LANGFLOW_BASE_VERSION\"" src/backend/base/pyproject.toml; then echo "$(RED)✗ Hanzo Flow-base pyproject.toml version validation failed$(NC)"; exit 1; fi; \
if ! grep -q "\"version\": \"$$LANGFLOW_VERSION\"" src/frontend/package.json; then echo "$(RED)✗ Frontend package.json version validation failed$(NC)"; exit 1; fi; \
echo "$(GREEN)✓ All versions updated successfully$(NC)"; \
\
@@ -715,7 +715,7 @@ load_test_lfx_quick: ## Quick LFX load test (30 users, 60s). Options: html=true,
# Enhanced load testing system with API-based flow loading
load_test_setup: ## Set up load test environment with starter project flows
@echo "$(YELLOW)Setting up Langflow load test environment$(NC)"
@echo "$(YELLOW)Setting up Hanzo Flow load test environment$(NC)"
@cd src/backend/tests/locust && uv run python langflow_setup_test.py --interactive
load_test_setup_basic: ## Set up load test environment with Basic Prompting flow
@@ -743,10 +743,10 @@ load_test_run: ## Run load test (automatically sets up if needed). Use FLOW_NAME
@cd src/backend/tests/locust && \
export API_KEY=$$(python -c "import json; print(json.load(open('load_test_creds.json'))['api_key'])") && \
export FLOW_ID=$$(python -c "import json; print(json.load(open('load_test_creds.json'))['flow_id'])") && \
uv run python langflow_run_load_test.py --headless --users 20 --duration 120 --no-start-langflow --html load_test_report.html --csv load_test_results
uv run python langflow_run_load_test.py --headless --users 20 --duration 120 --no-start-flow --html load_test_report.html --csv load_test_results
load_test_flow_quick: ## Quick Langflow load test (10 users, 30s) with HTML report (automatically sets up if needed). Use FLOW_NAME="Flow Name" to specify flow
@echo "$(YELLOW)Running quick Langflow load test with HTML report$(NC)"
load_test_flow_quick: ## Quick Hanzo Flow load test (10 users, 30s) with HTML report (automatically sets up if needed). Use FLOW_NAME="Flow Name" to specify flow
@echo "$(YELLOW)Running quick Hanzo Flow load test with HTML report$(NC)"
@if [ ! -f "src/backend/tests/locust/load_test_creds.json" ]; then \
echo "$(BLUE)No credentials found. Running automatic setup...$(NC)"; \
if [ -z "$(FLOW_NAME)" ]; then \
@@ -762,7 +762,7 @@ load_test_flow_quick: ## Quick Langflow load test (10 users, 30s) with HTML repo
@cd src/backend/tests/locust && \
export API_KEY=$$(python -c "import json; print(json.load(open('load_test_creds.json'))['api_key'])") && \
export FLOW_ID=$$(python -c "import json; print(json.load(open('load_test_creds.json'))['flow_id'])") && \
uv run python langflow_run_load_test.py --headless --users 10 --duration 30 --no-start-langflow --html quick_test_report.html
uv run python langflow_run_load_test.py --headless --users 10 --duration 30 --no-start-flow --html quick_test_report.html
load_test_stress: ## Stress test (100 users, 5 minutes) with comprehensive reporting (automatically sets up if needed). Use FLOW_NAME="Flow Name" to specify flow
@echo "$(YELLOW)Running stress test with comprehensive reporting$(NC)"
@@ -781,7 +781,7 @@ load_test_stress: ## Stress test (100 users, 5 minutes) with comprehensive repor
@cd src/backend/tests/locust && \
export API_KEY=$$(python -c "import json; print(json.load(open('load_test_creds.json'))['api_key'])") && \
export FLOW_ID=$$(python -c "import json; print(json.load(open('load_test_creds.json'))['flow_id'])") && \
uv run python langflow_run_load_test.py --headless --users 100 --spawn-rate 5 --duration 300 --no-start-langflow --html stress_test_report.html --csv stress_test_results --shape ramp100
uv run python langflow_run_load_test.py --headless --users 100 --spawn-rate 5 --duration 300 --no-start-flow --html stress_test_report.html --csv stress_test_results --shape ramp100
load_test_example: ## Run complete example workflow (setup + test + reports)
@echo "$(YELLOW)Running complete load test example workflow$(NC)"
@@ -814,14 +814,14 @@ load_test_remote_run: ## Run load test against remote instance (requires prior s
@cd src/backend/tests/locust && \
export API_KEY=$$(python -c "import json; print(json.load(open('remote_test_creds.json'))['api_key'])") && \
export FLOW_ID=$$(python -c "import json; print(json.load(open('remote_test_creds.json'))['flow_id'])") && \
uv run python langflow_run_load_test.py --host $(LANGFLOW_HOST) --no-start-langflow --headless --users 10 --spawn-rate 1 --duration 120 --html remote_test_report.html
uv run python langflow_run_load_test.py --host $(LANGFLOW_HOST) --no-start-flow --headless --users 10 --spawn-rate 1 --duration 120 --html remote_test_report.html
load_test_help: ## Show detailed load testing help
@echo "$(GREEN)Langflow Enhanced Load Testing System$(NC)"
@echo "$(GREEN)Hanzo Flow Enhanced Load Testing System$(NC)"
@echo ""
@echo "$(YELLOW)Quick Start (Local):$(NC)"
@echo " 1. make load_test_setup_basic # Set up with Basic Prompting flow"
@echo " 2. make load_test_flow_quick # Run quick Langflow test"
@echo " 2. make load_test_flow_quick # Run quick Hanzo Flow test"
@echo " 3. Open quick_test_report.html # View results"
@echo ""
@echo "$(YELLOW)Remote Testing:$(NC)"
@@ -834,7 +834,7 @@ load_test_help: ## Show detailed load testing help
@echo " load_test_setup_basic - Quick setup with Basic Prompting"
@echo " load_test_list_flows - List available starter flows"
@echo " load_test_run - Standard load test (25 users, 2 min)"
@echo " load_test_flow_quick - Quick Langflow test (10 users, 30s)"
@echo " load_test_flow_quick - Quick Hanzo Flow test (10 users, 30s)"
@echo " load_test_quick - Quick complex serve test (30 users, 60s)"
@echo " load_test_stress - Stress test (100 users, 5 min)"
@echo " load_test_example - Complete example workflow"
@@ -864,7 +864,7 @@ help_backend: ## show backend-specific commands
@echo ''
@echo "$(GREEN)Development:$(NC)"
@echo " $(GREEN)make backend$(NC) - Run backend in development mode"
@echo " $(GREEN)make run_cli$(NC) - Run Langflow CLI"
@echo " $(GREEN)make run_cli$(NC) - Run Hanzo Flow CLI"
@echo " $(GREEN)make run_clic$(NC) - Run CLI with fresh frontend build"
@echo " $(GREEN)make run_cli_debug$(NC) - Run CLI in debug mode"
@echo " $(GREEN)make setup_devcontainer$(NC) - Set up development container"
@@ -891,8 +891,8 @@ help_backend: ## show backend-specific commands
@echo " $(GREEN)make build$(NC) - Build the project"
@echo " $(GREEN)make build_and_run$(NC) - Build and run the project"
@echo " $(GREEN)make build_and_install$(NC) - Build and install the project"
@echo " $(GREEN)make build_flow_base$(NC) - Build langflow-base package"
@echo " $(GREEN)make build_langflow$(NC) - Build langflow package"
@echo " $(GREEN)make build_flow_base$(NC) - Build flow-base package"
@echo " $(GREEN)make build_langflow$(NC) - Build flow package"
@echo " $(GREEN)make lock$(NC) - Lock dependencies"
@echo " $(GREEN)make update$(NC) - Update dependencies"
@echo " $(GREEN)make publish$(NC) - Publish to PyPI"
@@ -1013,13 +1013,13 @@ help_advanced: ## show advanced and miscellaneous commands
@echo "$(GREEN)Version Management:$(NC)"
@echo " $(GREEN)make patch v=X.Y.Z$(NC) - Update version across all projects"
@echo " Example: make patch v=1.5.0"
@echo " This updates: pyproject.toml, langflow-base, frontend package.json"
@echo " This updates: pyproject.toml, flow-base, frontend package.json"
@echo ''
@echo "$(GREEN)Publishing:$(NC)"
@echo " $(GREEN)make publish$(NC) - Publish to PyPI (use: make publish base=1 or main=1)"
@echo " $(GREEN)make publish_testpypi$(NC) - Publish to test PyPI"
@echo " $(GREEN)make publish_base$(NC) - Publish langflow-base to PyPI"
@echo " $(GREEN)make publish_flow$(NC) - Publish langflow to PyPI"
@echo " $(GREEN)make publish_base$(NC) - Publish flow-base to PyPI"
@echo " $(GREEN)make publish_flow$(NC) - Publish flow to PyPI"
@echo " $(GREEN)make lfx_publish$(NC) - Publish LFX package to PyPI"
@echo " $(GREEN)make lfx_publish_testpypi$(NC) - Publish LFX to test PyPI"
@echo " $(GREEN)make sdk_publish$(NC) - Publish SDK package to PyPI"
@@ -1027,8 +1027,8 @@ help_advanced: ## show advanced and miscellaneous commands
@echo ''
@echo "$(GREEN)Lock Files:$(NC)"
@echo " $(GREEN)make lock$(NC) - Lock all dependencies"
@echo " $(GREEN)make lock_base$(NC) - Lock langflow-base dependencies"
@echo " $(GREEN)make lock_langflow$(NC) - Lock langflow dependencies"
@echo " $(GREEN)make lock_base$(NC) - Lock flow-base dependencies"
@echo " $(GREEN)make lock_langflow$(NC) - Lock flow dependencies"
@echo ''
@echo "$(GREEN)Utilities:$(NC)"
@echo " $(GREEN)make check_tools$(NC) - Verify required tools are installed"
@@ -1075,7 +1075,7 @@ docs_serve: docs_build ## build and serve documentation locally
# Note: $(or $(suites),a,b,c) is wrong here — GNU make's `or` returns only the first non-empty token.
suites ?= curl,python,javascript
api_examples_local: ## run docs API sample files against a local Langflow server
api_examples_local: ## run docs API sample files against a local Hanzo Flow server
@echo "$(GREEN)Running docs API examples locally...$(NC)"
@SUITES="$(suites)" EXECUTE_MODE=true ./scripts/test-api-examples-local.sh
+3 -3
View File
@@ -1,4 +1,4 @@
# Frontend-specific Makefile for Langflow
# Frontend-specific Makefile for Hanzo Flow
# This file contains all frontend-related targets
# Variables
@@ -40,9 +40,9 @@ build_frontend: ## build the frontend static files
@echo 'Building frontend static files...'
@cd $(FRONTEND_DIR) && CI='' npm run build 2>&1 || { echo "\nBuild failed! Error output above ☝️"; exit 1; }
@echo 'Clearing destination directory...'
$(call CLEAR_DIRS,src/backend/base/langflow/frontend)
$(call CLEAR_DIRS,src/backend/base/flow/frontend)
@echo 'Copying build files...'
@cp -r $(FRONTEND_DIR)/build/. src/backend/base/langflow/frontend
@cp -r $(FRONTEND_DIR)/build/. src/backend/base/flow/frontend
@echo '==== Frontend build complete ===='
######################
+2 -2
View File
@@ -1,6 +1,6 @@
flow
Copyright (c) 2024-2026 Hanzo AI, Inc.
This product includes software from Langflow (https://github.com/langflow-ai/langflow), licensed under the MIT License:
This product includes software from Hanzo Flow (https://github.com/hanzoai/flow), licensed under the MIT License:
Copyright (c) 2024 Langflow
Copyright (c) 2024 Hanzo Flow
+8 -8
View File
@@ -42,7 +42,7 @@ We appreciate your efforts in helping us maintain a secure platform and look for
## Known Vulnerabilities
> **Note**: Hanzo Flow is based on the upstream Langflow project. The CVEs and GitHub Advisories below link to the original upstream disclosures for reference.
> **Note**: Hanzo Flow is based on the upstream Hanzo Flow project. The CVEs and GitHub Advisories below link to the original upstream disclosures for reference.
### Server-Side Request Forgery (SSRF) in API Request Component (Fixed in 1.7.1)
@@ -54,7 +54,7 @@ The API Request component allows arbitrary HTTP requests within a flow. In versi
- Non-blind SSRF: Response bodies are returned to the client, enabling immediate data exfiltration
**CVE**: [CVE-2025-68477](https://nvd.nist.gov/vuln/detail/CVE-2025-68477)
**GitHub Advisory**: [GHSA-5993-7p27-66g5](https://github.com/langflow-ai/langflow/security/advisories/GHSA-5993-7p27-66g5)
**GitHub Advisory**: [GHSA-5993-7p27-66g5](https://github.com/hanzoai/flow/security/advisories/GHSA-5993-7p27-66g5)
**Fixed in**: >= 1.7.1
### External Control of File Name or Path (Fixed in 1.7.1)
@@ -68,7 +68,7 @@ When creating a flow through the `/api/v1/flows/` endpoint, if an arbitrary path
- File content is limited to Flow JSON, but impact is severe if the target file is parsed by a JSON parser or subject to subsequent processing
**CVE**: [CVE-2025-68478](https://nvd.nist.gov/vuln/detail/CVE-2025-68478)
**GitHub Advisory**: [GHSA-f43r-cc68-gpx4](https://github.com/langflow-ai/langflow/security/advisories/GHSA-f43r-cc68-gpx4)
**GitHub Advisory**: [GHSA-f43r-cc68-gpx4](https://github.com/hanzoai/flow/security/advisories/GHSA-f43r-cc68-gpx4)
**Fixed in**: >= 1.7.1
### Environment Variable Loading Bug (Fixed in 1.6.4)
@@ -95,9 +95,9 @@ This means an attacker could send malicious code to the endpoint and have it exe
### Privilege Escalation via CLI Superuser Creation (Fixed in 1.5.1)
A privilege escalation vulnerability exists in containers where an authenticated user with RCE access can invoke the internal CLI command `langflow superuser` to create a new administrative user. This results in full superuser access, even if the user initially registered through the UI as a regular (non-admin) account.
A privilege escalation vulnerability exists in containers where an authenticated user with RCE access can invoke the internal CLI command `flow superuser` to create a new administrative user. This results in full superuser access, even if the user initially registered through the UI as a regular (non-admin) account.
**CVE**: [CVE-2025-57760](https://github.com/langflow-ai/langflow/security/advisories/GHSA-4gv9-mp8m-592r)
**CVE**: [CVE-2025-57760](https://github.com/hanzoai/flow/security/advisories/GHSA-4gv9-mp8m-592r)
**Fixed in**: >= 1.5.1
### No API key required when running with `LANGFLOW_AUTO_LOGIN=true` and `LANGFLOW_SKIP_AUTH_AUTO_LOGIN=true`
@@ -115,7 +115,7 @@ For more information, see the API keys and authentication documentation.
### Superuser Creation Security
The `langflow superuser` CLI command can present a privilege escalation risk if not properly secured.
The `flow superuser` CLI command can present a privilege escalation risk if not properly secured.
#### Security Measures
@@ -129,7 +129,7 @@ The `langflow superuser` CLI command can present a privilege escalation risk if
3. **Secure AUTO_LOGIN Setting**
- Default is `true` for <=1.5. This may change in a future release.
- When `true`, creates default superuser `langflow/langflow` - **ONLY USE IN DEVELOPMENT**
- When `true`, creates default superuser `flow/flow` - **ONLY USE IN DEVELOPMENT**
#### Production Security Configuration
@@ -139,6 +139,6 @@ export LANGFLOW_AUTO_LOGIN=false
export LANGFLOW_ENABLE_SUPERUSER_CLI=false
export LANGFLOW_SUPERUSER="<your-superuser-username>"
export LANGFLOW_SUPERUSER_PASSWORD="<your-superuser-password>"
export LANGFLOW_DATABASE_URL="<your-production-database-url>" # e.g. "postgresql+psycopg://langflow:secure_pass@db.internal:5432/langflow"
export LANGFLOW_DATABASE_URL="<your-production-database-url>" # e.g. "postgresql+psycopg://flow:secure_pass@db.internal:5432/flow"
export LANGFLOW_SECRET_KEY="your-strong-random-secret-key"
```
+1 -1
View File
@@ -15,7 +15,7 @@
//
// studio = Run(GPUResident, Graph-of-Tensor-steps) // comfy nodes
// automations = Run(Durable, Graph-of-ConnectorIO) // triggers -> actions
// llmFlow = Run(InProcess, Graph-of-Message-steps) // langflow (lfx) nodes
// llmFlow = Run(InProcess, Graph-of-Message-steps) // flow (lfx) nodes
//
// A domain supplies Steps (typed input ports -> typed output ports + a Run fn) and,
// if it has special execution needs, a Backend for a Mode. The engine only wires
+14 -14
View File
@@ -1,40 +1,40 @@
DOMAIN=localhost
STACK_NAME=langflow-stack
STACK_NAME=flow-stack
TRAEFIK_PUBLIC_NETWORK=traefik-public
TRAEFIK_TAG=langflow-traefik
TRAEFIK_TAG=flow-traefik
TRAEFIK_PUBLIC_TAG=traefik-public
# Langflow backend configuration
# Hanzo Flow backend configuration
LANGFLOW_LOG_LEVEL=debug
LANGFLOW_SUPERUSER=superuser
LANGFLOW_SUPERUSER_PASSWORD=superuser
LANGFLOW_NEW_USER_IS_ACTIVE=False
# Langflow frontend configuration
# Hanzo Flow frontend configuration
BACKEND_URL=http://backend:7860
# RabbitMQ configuration
RABBITMQ_DEFAULT_USER=langflow
RABBITMQ_DEFAULT_PASS=langflow
RABBITMQ_DEFAULT_USER=flow
RABBITMQ_DEFAULT_PASS=flow
# Database configuration
DB_USER=langflow
DB_PASSWORD=langflow
DB_USER=flow
DB_PASSWORD=flow
DB_HOST=db
DB_PORT=5432
DB_NAME=langflow
DB_NAME=flow
# DB configuration
POSTGRES_USER=langflow
POSTGRES_PASSWORD=langflow
POSTGRES_DB=langflow
POSTGRES_USER=flow
POSTGRES_PASSWORD=flow
POSTGRES_DB=flow
POSTGRES_PORT=5432
# Flower configuration
# Disable until https://github.com/langflow-ai/langflow/pull/2655 gets released
# Disable until https://github.com/hanzoai/flow/pull/2655 gets released
#LANGFLOW_CACHE_TYPE=redis
LANGFLOW_REDIS_HOST=result_backend
LANGFLOW_REDIS_PORT=6379
@@ -42,7 +42,7 @@ LANGFLOW_REDIS_DB=0
LANGFLOW_REDIS_EXPIRE=3600
LANGFLOW_REDIS_PASSWORD=
FLOWER_UNAUTHENTICATED_API=True
BROKER_URL=amqp://langflow:langflow@broker:5672
BROKER_URL=amqp://flow:flow@broker:5672
RESULT_BACKEND=redis://result_backend:6379/0
C_FORCE_ROOT="true"
+9 -9
View File
@@ -65,7 +65,7 @@ WORKDIR /tmp/src/frontend
RUN --mount=type=cache,target=/root/.npm \
npm ci \
&& ESBUILD_BINARY_PATH="" NODE_OPTIONS="--max-old-space-size=4096" JOBS=1 npm run build \
&& cp -r build /app/src/backend/langflow/frontend \
&& cp -r build /app/src/backend/flow/frontend \
&& rm -rf /tmp/src/frontend
WORKDIR /app
@@ -106,18 +106,18 @@ ENV PATH="/app/.venv/bin:$PATH"
# Pre-create LANGFLOW_CONFIG_DIR (the default location used by the docker_example
# compose file) with the non-root user as owner. When the official compose mounts
# a fresh named volume at /app/langflow, Docker copies this directory's ownership
# a fresh named volume at /app/flow, Docker copies this directory's ownership
# and permissions into the new volume, so the in-container uid=1000 user can
# write secret_key, profile_pictures, etc. Without this, the volume is created
# as root:root and Langflow crashes during startup with PermissionError on
# /app/langflow/secret_key. See https://github.com/langflow-ai/langflow/issues/10437
RUN mkdir -p /app/langflow && chown -R 1000:0 /app/langflow && chmod -R g+rwX /app/langflow
# as root:root and Hanzo Flow crashes during startup with PermissionError on
# /app/flow/secret_key. See https://github.com/hanzoai/flow/issues/10437
RUN mkdir -p /app/flow && chown -R 1000:0 /app/flow && chmod -R g+rwX /app/flow
LABEL org.opencontainers.image.title=langflow
LABEL org.opencontainers.image.authors=['Langflow']
LABEL org.opencontainers.image.title=flow
LABEL org.opencontainers.image.authors=['Hanzo Flow']
LABEL org.opencontainers.image.licenses=MIT
LABEL org.opencontainers.image.url=https://github.com/langflow-ai/langflow
LABEL org.opencontainers.image.source=https://github.com/langflow-ai/langflow
LABEL org.opencontainers.image.url=https://github.com/hanzoai/flow
LABEL org.opencontainers.image.source=https://github.com/hanzoai/flow
USER user
WORKDIR /app
+15 -15
View File
@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1
# Keep this syntax directive! It's used to enable Docker BuildKit
#
# Backend-only Langflow image
# Backend-only Hanzo Flow image
# - No frontend code or assets
# - No Playwright
@@ -31,13 +31,13 @@ COPY ./src/backend ./src/backend
COPY ./src/lfx ./src/lfx
COPY ./src/sdk ./src/sdk
# Create venv and install langflow-base with dependencies
# Create venv and install flow-base with dependencies
# Using uv pip instead of uv sync to avoid workspace complexities
RUN uv venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"
ENV VIRTUAL_ENV="/app/.venv"
# Install langflow-base with all extras except dev (which includes Playwright)
# Install flow-base with all extras except dev (which includes Playwright)
RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install ./src/sdk ./src/lfx "./src/backend/base[complete,postgresql]"
@@ -80,23 +80,23 @@ ENV PATH="/app/.venv/bin:$PATH"
# Create home directory and ensure proper ownership
# The user needs write access to /app/data (home) and /app (workdir).
# Also pre-create /app/langflow (LANGFLOW_CONFIG_DIR used by the docker_example
# Also pre-create /app/flow (LANGFLOW_CONFIG_DIR used by the docker_example
# compose file) with the non-root user as owner, so a fresh named volume mounted
# at /app/langflow inherits the correct ownership/permissions and the in-container
# at /app/flow inherits the correct ownership/permissions and the in-container
# uid=1000 user can write secret_key, profile_pictures, etc. Without this, the
# volume would be initialized as root:root and Langflow would crash with
# PermissionError on /app/langflow/secret_key (issue #10437).
# volume would be initialized as root:root and Hanzo Flow would crash with
# PermissionError on /app/flow/secret_key (issue #10437).
# Note: .venv is already owned by 1000:0 via COPY --chown above, so no recursive chown needed
RUN mkdir -p /app/data /app/langflow \
&& chown -R 1000:0 /app/data /app/langflow \
&& chmod -R g+rwX /app/langflow \
RUN mkdir -p /app/data /app/flow \
&& chown -R 1000:0 /app/data /app/flow \
&& chmod -R g+rwX /app/flow \
&& chown 1000:0 /app
LABEL org.opencontainers.image.title=langflow-backend
LABEL org.opencontainers.image.authors=['Langflow']
LABEL org.opencontainers.image.title=flow-backend
LABEL org.opencontainers.image.authors=['Hanzo Flow']
LABEL org.opencontainers.image.licenses=MIT
LABEL org.opencontainers.image.url=https://github.com/langflow-ai/langflow
LABEL org.opencontainers.image.source=https://github.com/langflow-ai/langflow
LABEL org.opencontainers.image.url=https://github.com/hanzoai/flow
LABEL org.opencontainers.image.source=https://github.com/hanzoai/flow
USER user
WORKDIR /app
@@ -104,4 +104,4 @@ WORKDIR /app
ENV LANGFLOW_HOST=0.0.0.0
ENV LANGFLOW_PORT=7860
CMD ["python", "-m", "langflow", "run", "--backend-only"]
CMD ["python", "-m", "flow", "run", "--backend-only"]
+10 -10
View File
@@ -64,7 +64,7 @@ WORKDIR /tmp/src/frontend
# Force esbuild to use JS implementation on emulated architectures to avoid native binary crashes
RUN npm install \
&& ESBUILD_BINARY_PATH="" NODE_OPTIONS="--max-old-space-size=4096" JOBS=1 npm run build \
&& cp -r build /app/src/backend/base/langflow/frontend \
&& cp -r build /app/src/backend/base/flow/frontend \
&& rm -rf /tmp/src/frontend
WORKDIR /app/src/backend/base
@@ -103,18 +103,18 @@ ENV PATH="/app/.venv/bin:$PATH"
# Pre-create LANGFLOW_CONFIG_DIR (the default location used by the docker_example
# compose file) with the non-root user as owner. When the official compose mounts
# a fresh named volume at /app/langflow, Docker copies this directory's ownership
# a fresh named volume at /app/flow, Docker copies this directory's ownership
# and permissions into the new volume, so the in-container uid=1000 user can
# write secret_key, profile_pictures, etc. Without this, the volume is created
# as root:root and Langflow crashes during startup with PermissionError on
# /app/langflow/secret_key. See https://github.com/langflow-ai/langflow/issues/10437
RUN mkdir -p /app/langflow && chown -R 1000:0 /app/langflow && chmod -R g+rwX /app/langflow
# as root:root and Hanzo Flow crashes during startup with PermissionError on
# /app/flow/secret_key. See https://github.com/hanzoai/flow/issues/10437
RUN mkdir -p /app/flow && chown -R 1000:0 /app/flow && chmod -R g+rwX /app/flow
LABEL org.opencontainers.image.title=langflow
LABEL org.opencontainers.image.authors=['Langflow']
LABEL org.opencontainers.image.title=flow
LABEL org.opencontainers.image.authors=['Hanzo Flow']
LABEL org.opencontainers.image.licenses=MIT
LABEL org.opencontainers.image.url=https://github.com/langflow-ai/langflow
LABEL org.opencontainers.image.source=https://github.com/langflow-ai/langflow
LABEL org.opencontainers.image.url=https://github.com/hanzoai/flow
LABEL org.opencontainers.image.source=https://github.com/hanzoai/flow
USER user
WORKDIR /app
@@ -122,4 +122,4 @@ WORKDIR /app
ENV LANGFLOW_HOST=0.0.0.0
ENV LANGFLOW_PORT=7860
CMD ["langflow-base", "run"]
CMD ["flow-base", "run"]
+10 -10
View File
@@ -58,7 +58,7 @@ WORKDIR /tmp/src/frontend
RUN --mount=type=cache,target=/root/.npm \
npm ci \
&& ESBUILD_BINARY_PATH="" NODE_OPTIONS="--max-old-space-size=4096" JOBS=1 npm run build \
&& cp -r build /app/src/backend/langflow/frontend \
&& cp -r build /app/src/backend/flow/frontend \
&& rm -rf /tmp/src/frontend
WORKDIR /app
@@ -97,18 +97,18 @@ ENV PATH="/app/.venv/bin:$PATH"
# Pre-create LANGFLOW_CONFIG_DIR (the default location used by the docker_example
# compose file) with the non-root user as owner. When the official compose mounts
# a fresh named volume at /app/langflow, Docker copies this directory's ownership
# a fresh named volume at /app/flow, Docker copies this directory's ownership
# and permissions into the new volume, so the in-container uid=1000 user can
# write secret_key, profile_pictures, etc. Without this, the volume is created
# as root:root and Langflow crashes during startup with PermissionError on
# /app/langflow/secret_key. See https://github.com/langflow-ai/langflow/issues/10437
RUN mkdir -p /app/langflow && chown -R 1000:0 /app/langflow && chmod -R g+rwX /app/langflow
# as root:root and Hanzo Flow crashes during startup with PermissionError on
# /app/flow/secret_key. See https://github.com/hanzoai/flow/issues/10437
RUN mkdir -p /app/flow && chown -R 1000:0 /app/flow && chmod -R g+rwX /app/flow
LABEL org.opencontainers.image.title=langflow
LABEL org.opencontainers.image.authors=['Langflow']
LABEL org.opencontainers.image.title=flow
LABEL org.opencontainers.image.authors=['Hanzo Flow']
LABEL org.opencontainers.image.licenses=MIT
LABEL org.opencontainers.image.url=https://github.com/langflow-ai/langflow
LABEL org.opencontainers.image.source=https://github.com/langflow-ai/langflow
LABEL org.opencontainers.image.url=https://github.com/hanzoai/flow
LABEL org.opencontainers.image.source=https://github.com/hanzoai/flow
WORKDIR /app
@@ -117,4 +117,4 @@ ENV LANGFLOW_PORT=7860
ENV LANGFLOW_EVENT_DELIVERY=polling
USER 1000
CMD ["python", "-m", "langflow", "run", "--host", "0.0.0.0", "--backend-only"]
CMD ["python", "-m", "flow", "run", "--host", "0.0.0.0", "--backend-only"]
+10 -10
View File
@@ -58,7 +58,7 @@ WORKDIR /tmp/src/frontend
RUN --mount=type=cache,target=/root/.npm \
npm ci \
&& ESBUILD_BINARY_PATH="" NODE_OPTIONS="--max-old-space-size=4096" JOBS=1 npm run build \
&& cp -r build /app/src/backend/langflow/frontend \
&& cp -r build /app/src/backend/flow/frontend \
&& rm -rf /tmp/src/frontend
WORKDIR /app
@@ -98,18 +98,18 @@ ENV PATH="/app/.venv/bin:$PATH"
# Pre-create LANGFLOW_CONFIG_DIR (the default location used by the docker_example
# compose file) with the non-root user as owner. When the official compose mounts
# a fresh named volume at /app/langflow, Docker copies this directory's ownership
# a fresh named volume at /app/flow, Docker copies this directory's ownership
# and permissions into the new volume, so the in-container uid=1000 user can
# write secret_key, profile_pictures, etc. Without this, the volume is created
# as root:root and Langflow crashes during startup with PermissionError on
# /app/langflow/secret_key. See https://github.com/langflow-ai/langflow/issues/10437
RUN mkdir -p /app/langflow && chown -R 1000:0 /app/langflow && chmod -R g+rwX /app/langflow
# as root:root and Hanzo Flow crashes during startup with PermissionError on
# /app/flow/secret_key. See https://github.com/hanzoai/flow/issues/10437
RUN mkdir -p /app/flow && chown -R 1000:0 /app/flow && chmod -R g+rwX /app/flow
LABEL org.opencontainers.image.title=langflow
LABEL org.opencontainers.image.authors=['Langflow']
LABEL org.opencontainers.image.title=flow
LABEL org.opencontainers.image.authors=['Hanzo Flow']
LABEL org.opencontainers.image.licenses=MIT
LABEL org.opencontainers.image.url=https://github.com/langflow-ai/langflow
LABEL org.opencontainers.image.source=https://github.com/langflow-ai/langflow
LABEL org.opencontainers.image.url=https://github.com/hanzoai/flow
LABEL org.opencontainers.image.source=https://github.com/hanzoai/flow
USER user
WORKDIR /app
@@ -117,4 +117,4 @@ WORKDIR /app
ENV LANGFLOW_HOST=0.0.0.0
ENV LANGFLOW_PORT=7860
CMD ["langflow", "run"]
CMD ["flow", "run"]
@@ -16,10 +16,10 @@ RUN cd /frontend && npm install && npm run build
################################
FROM ghcr.io/hanzoai/static:latest AS runtime
LABEL org.opencontainers.image.title=langflow-frontend
LABEL org.opencontainers.image.authors=['Langflow']
LABEL org.opencontainers.image.title=flow-frontend
LABEL org.opencontainers.image.authors=['Hanzo Flow']
LABEL org.opencontainers.image.licenses=MIT
LABEL org.opencontainers.image.url=https://github.com/langflow-ai/langflow
LABEL org.opencontainers.image.source=https://github.com/langflow-ai/langflow
LABEL org.opencontainers.image.url=https://github.com/hanzoai/flow
LABEL org.opencontainers.image.source=https://github.com/hanzoai/flow
COPY --from=builder-base /frontend/build /srv
+13 -13
View File
@@ -1,33 +1,33 @@
services:
langflow:
image: langflowai/langflow:latest # or another version tag on https://hub.docker.com/r/langflowai/langflow
flow:
image: langflowai/flow:latest # or another version tag on https://hub.docker.com/r/langflowai/flow
pull_policy: always # set to 'always' when using 'latest' image
ports:
- "7860:7860"
depends_on:
- postgres
environment:
- LANGFLOW_DATABASE_URL=postgresql://langflow:langflow@postgres:5432/langflow
- LANGFLOW_DATABASE_URL=postgresql://flow:flow@postgres:5432/flow
# This variable defines where the logs, file storage, monitor data and secret keys are stored.
- LANGFLOW_CONFIG_DIR=/app/langflow
- LANGFLOW_CONFIG_DIR=/app/flow
volumes:
- langflow-data:/app/langflow
- flow-data:/app/flow
postgres:
# Pinned to a specific Debian base (trixie) so the postgres:16 tag does not
# silently roll its OS underneath us — that roll causes a glibc collation
# version mismatch warning on existing volumes. Matches the langflow image
# base. See https://github.com/langflow-ai/langflow/issues/9608
# version mismatch warning on existing volumes. Matches the flow image
# base. See https://github.com/hanzoai/flow/issues/9608
image: postgres:16-trixie
environment:
POSTGRES_USER: langflow
POSTGRES_PASSWORD: langflow
POSTGRES_DB: langflow
POSTGRES_USER: flow
POSTGRES_PASSWORD: flow
POSTGRES_DB: flow
ports:
- "5432:5432"
volumes:
- langflow-postgres:/var/lib/postgresql/data
- flow-postgres:/var/lib/postgresql/data
volumes:
langflow-postgres:
langflow-data:
flow-postgres:
flow-data:
+2 -2
View File
@@ -17,8 +17,8 @@ services:
postgres:
# Pinned to a specific Debian base (trixie) so the postgres:16 tag does not
# silently roll its OS underneath us — that roll causes a glibc collation
# version mismatch warning on existing volumes. Matches the langflow image
# base. See https://github.com/langflow-ai/langflow/issues/9608
# version mismatch warning on existing volumes. Matches the flow image
# base. See https://github.com/hanzoai/flow/issues/9608
image: postgres:16-trixie
environment:
POSTGRES_USER: hanzoflow
+14 -14
View File
@@ -1,4 +1,4 @@
# Investigation: Deprecated macOS Support — Impact on Langflow
# Investigation: Deprecated macOS Support — Impact on Hanzo Flow
**Jira:** LE-265
**Date:** 2026-04-02
@@ -9,9 +9,9 @@
## TL;DR
macOS Intel (x86_64) is in its final phase of deprecation across the entire ecosystem — Apple hardware, operating system, GitHub Actions runners, PyTorch, and the broader ML/AI stack. Langflow already has platform exclusion markers for the most critical torch-dependent extras (PR #12469), but additional deprecations in GitHub Actions runners, macOS versions, and upstream dependencies will require further action over the next 12–18 months.
macOS Intel (x86_64) is in its final phase of deprecation across the entire ecosystem — Apple hardware, operating system, GitHub Actions runners, PyTorch, and the broader ML/AI stack. Hanzo Flow already has platform exclusion markers for the most critical torch-dependent extras (PR #12469), but additional deprecations in GitHub Actions runners, macOS versions, and upstream dependencies will require further action over the next 12–18 months.
**Key decision required:** Set a timeline to officially drop macOS x86_64 from Langflow's support matrix (recommended: Langflow 2.0 or Q4 2026, whichever comes first).
**Key decision required:** Set a timeline to officially drop macOS x86_64 from Hanzo Flow's support matrix (recommended: Hanzo Flow 2.0 or Q4 2026, whichever comes first).
---
@@ -68,7 +68,7 @@ macOS Intel (x86_64) is in its final phase of deprecation across the entire ecos
---
## 2. Current State of Langflow macOS Support
## 2. Current State of Hanzo Flow macOS Support
### 2.1 Platform Exclusion Markers in `pyproject.toml`
@@ -118,7 +118,7 @@ The following extras have platform markers excluding macOS x86_64 (**as of PR #1
### 3.1 What Works on macOS x86_64 Today
Langflow **core functionality** (flow builder, API, database, all non-ML components) works on macOS Intel with Python 3.10–3.13. The following features are **unavailable**:
Hanzo Flow **core functionality** (flow builder, API, database, all non-ML components) works on macOS Intel with Python 3.10–3.13. The following features are **unavailable**:
- ALTK (Agent Lifecycle Toolkit) components
- HuggingFace/sentence-transformers embeddings
@@ -132,7 +132,7 @@ Langflow **core functionality** (flow builder, API, database, all non-ML compone
### 3.2 What Will Break Next
| Timeline | Event | Impact on Langflow |
| Timeline | Event | Impact on Hanzo Flow |
|----------|-------|--------------------|
| **Now** | PyTorch has no Intel Mac wheels for Python 3.13+ | Already mitigated (PR #12469) |
| **Q3 2026** | GitHub may deprecate `macos-latest-large` (Intel) | Stable CI tests for macOS Intel would need migration or removal |
@@ -160,7 +160,7 @@ PR #12469 has already addressed the most critical issue:
- ✅ `mlx`, `cuga` are ARM64-only
- ✅ Experimental CI uses `continue-on-error: true`
### 4.2 Short-Term (Langflow 1.10 / Q2 2026)
### 4.2 Short-Term (Hanzo Flow 1.10 / Q2 2026)
#### ~~R1: Add `platform_machine` marker to `metal` extra~~ — NOT NEEDED
@@ -184,7 +184,7 @@ Remove the Python 3.10 stable test on macOS AMD64. Python 3.12 is the most commo
Add a support matrix page to `docs/` clarifying which features require Apple Silicon vs. work on Intel, so users have clear expectations.
### 4.3 Medium-Term (Langflow 2.0 / Q4 2026)
### 4.3 Medium-Term (Hanzo Flow 2.0 / Q4 2026)
#### R4: Drop macOS x86_64 from CI entirely
@@ -205,11 +205,11 @@ The `OBJC_DISABLE_INITIALIZE_FORK_SAFETY` workaround in `__main__.py` and `langf
#### R6: Officially deprecate macOS x86_64 in release notes
Add a deprecation notice in the Langflow 2.0 release notes:
Add a deprecation notice in the Hanzo Flow 2.0 release notes:
> **macOS Intel (x86_64) support is deprecated.** Langflow 2.0 is the last version tested on Intel Macs. Future releases will only be tested on Apple Silicon (ARM64). Core functionality may continue to work, but ML features require Apple Silicon.
> **macOS Intel (x86_64) support is deprecated.** Hanzo Flow 2.0 is the last version tested on Intel Macs. Future releases will only be tested on Apple Silicon (ARM64). Core functionality may continue to work, but ML features require Apple Silicon.
### 4.4 Long-Term (Langflow 2.x+ / 2027)
### 4.4 Long-Term (Hanzo Flow 2.x+ / 2027)
#### R7: Remove all macOS x86_64 platform markers
@@ -240,7 +240,7 @@ With Intel out of the picture, lean into Apple Silicon capabilities:
| GitHub removes `macos-latest-large` runner | High (12–18 months) | CI breaks for Intel tests | R4: Drop Intel from CI proactively |
| User complaints about missing ML features on Intel Mac | Low | User frustration | R3: Document support matrix clearly |
| ~~`metal_sdk` fails on Intel Mac install~~ | N/A | N/A | `metal_sdk` is getmetal.io cloud SDK — cross-platform, no issue |
| Python 3.14 drops macOS x86_64 support | Low (2027+) | Core Langflow broken on Intel | R6: Deprecation notice well in advance |
| Python 3.14 drops macOS x86_64 support | Low (2027+) | Core Hanzo Flow broken on Intel | R6: Deprecation notice well in advance |
| OBJC fork safety workaround breaks on new macOS | Low | Server startup crash | R5: Audit and test on macOS 26 |
| Upstream deps (numpy, scipy) drop Intel Mac wheels | Medium (2027+) | Broad installation failures | R6/R7: Official deprecation covers this |
@@ -248,7 +248,7 @@ With Intel out of the picture, lean into Apple Silicon capabilities:
## 6. Recommended macOS Support Matrix
### Current (Langflow 1.9.x)
### Current (Hanzo Flow 1.9.x)
| Feature Category | macOS ARM64 (Apple Silicon) | macOS x86_64 (Intel) |
|-----------------|---------------------------|---------------------|
@@ -259,7 +259,7 @@ With Intel out of the picture, lean into Apple Silicon capabilities:
| GPU acceleration (Metal, CUGA) | ✅ Full support | ❌ Not available (ARM64 only) |
| Native OCR (ocrmac) | ✅ Full support | ✅ Full support |
### Proposed (Langflow 2.0+)
### Proposed (Hanzo Flow 2.0+)
| Feature Category | macOS ARM64 (Apple Silicon) | macOS x86_64 (Intel) |
|-----------------|---------------------------|---------------------|
@@ -8,7 +8,7 @@
## TL;DR
**PyTorch officially dropped macOS x86_64 (Intel) binary support after version 2.2.2** (milestone: PyTorch 2.3, March 2024). Since Python 3.13 was released in October 2024 — after this cutoff — **no official PyTorch wheel exists for macOS x86_64 + Python 3.13**. This is an upstream, permanent gap — not a bug in Langflow.
**PyTorch officially dropped macOS x86_64 (Intel) binary support after version 2.2.2** (milestone: PyTorch 2.3, March 2024). Since Python 3.13 was released in October 2024 — after this cutoff — **no official PyTorch wheel exists for macOS x86_64 + Python 3.13**. This is an upstream, permanent gap — not a bug in Hanzo Flow.
The failing CI job is `test-installation-experimental` on `macos-latest-large` (AMD64) with Python 3.13. The `continue-on-error: true` flag means it doesn't block releases, but the failure is persistent and expected.
@@ -42,7 +42,7 @@ The resolver picks `torch 2.2.2+cpu` for macOS x86_64 + Python 3.13, but **this
### 3. How Torch Gets Pulled In
The main `langflow` package depends on `langflow-base[complete]`, which includes multiple extras that transitively require torch:
The main `flow` package depends on `flow-base[complete]`, which includes multiple extras that transitively require torch:
#### Dependency Chains to Torch
@@ -95,7 +95,7 @@ langchain-huggingface = ["langchain-huggingface==0.3.1; sys_platform != 'darwin'
**Pros:**
- CI will pass on all experimental platforms
- macOS x86_64 users on Python 3.13 can still use Langflow (just without ALTK/HuggingFace features)
- macOS x86_64 users on Python 3.13 can still use Hanzo Flow (just without ALTK/HuggingFace features)
- Consistent with existing pattern for docling/easyocr
**Cons:**
+5 -5
View File
@@ -25,8 +25,8 @@ These are battle scars. Every rule here cites a real recurring failure: a commit
7. **Don't invent model IDs, MCP tool names, or API surface.** Read the registry, the batch dispatcher, and `models.py` first.
*Why:* `9f1402ed9` (`remove fictional gpt-5.3 ids`), `cecc4a6c2` (`expose layout tool as layout_flow to match batch dispatch`).
8. **Don't use raw `langflow run` / `python` when a `uv` command exists.** Always `uv run`. For lfx tests specifically: `uv sync` inside `src/lfx` (not `src/lfx/src/lfx`) to avoid pulling in langflow.
*Why:* lfx must be testable without langflow installed; mixing them masks dependency leaks.
8. **Don't use raw `flow run` / `python` when a `uv` command exists.** Always `uv run`. For lfx tests specifically: `uv sync` inside `src/lfx` (not `src/lfx/src/lfx`) to avoid pulling in flow.
*Why:* lfx must be testable without flow installed; mixing them masks dependency leaks.
9. **Don't add a database migration without running `make alembic-upgrade` end to end** and `uv run pytest src/backend/tests/unit/test_database.py` sequentially.
*Why:* `d8b9cc38f`, `c30150a2d`, `6585fe661`. `test_database.py` may pass in batch and fail individually — agents have stopped running it.
@@ -69,11 +69,11 @@ These are battle scars. Every rule here cites a real recurring failure: a commit
## Where to look for context — don't invent it
- **Starter projects:** `src/backend/base/langflow/initial_setup/starter_projects/`. Any field/output change must regenerate these.
- **Starter projects:** `src/backend/base/flow/initial_setup/starter_projects/`. Any field/output change must regenerate these.
- **Component index:** `src/lfx/src/lfx/_assets/component_index.json` (rebuilt via the index sync workflow added in `9dad1965c`).
- **Output type migrations:** `src/backend/base/langflow/initial_setup/setup.py` `type_migrations` map — handles renames of *output type strings* (e.g., `Data` → `JSON`). It does NOT remap component class names; for class renames use `legacy=True` + `replacement=[...]`.
- **Output type migrations:** `src/backend/base/flow/initial_setup/setup.py` `type_migrations` map — handles renames of *output type strings* (e.g., `Data` → `JSON`). It does NOT remap component class names; for class renames use `legacy=True` + `replacement=[...]`.
- **Version mapping for component tests:** `src/backend/tests/constants.py::SUPPORTED_VERSIONS` and each test's `file_names_mapping`.
- **Release notes / changelog:** `docs/docs/Support/release-notes/` — check before claiming behavior is "new"; many features predate the current task.
- **MCP tool catalog:** dispatched via the batch tool — names must match (`cecc4a6c2` is the canonical "I guessed the tool name" failure).
- **Models / providers:** real model IDs come from the provider's listing endpoint or our adapter, never from training-data memory (`9f1402ed9`).
- **Migrations:** `src/backend/base/langflow/alembic/versions/` — always read the latest two before adding a new one.
- **Migrations:** `src/backend/base/flow/alembic/versions/` — always read the latest two before adding a new one.
+16 -16
View File
@@ -1,14 +1,14 @@
# Architecture Boundaries
Langflow is three Python packages and one frontend, layered with one-way dependencies. Most "off-narrative" code is a boundary violation. Read this before adding a new file.
Hanzo Flow is three Python packages and one frontend, layered with one-way dependencies. Most "off-narrative" code is a boundary violation. Read this before adding a new file.
## Package dependency graph (one-way only)
```
frontend (TS) ──HTTP──▶ langflow (api routers, integrations, distribution)
frontend (TS) ──HTTP──▶ flow (api routers, integrations, distribution)
│
▼ may import
langflow-base (services, graph, db, alembic)
flow-base (services, graph, db, alembic)
│
▼ may import
lfx (executor core, base primitives, components)
@@ -19,9 +19,9 @@ frontend (TS) ──HTTP──▶ langflow (api routers, integrations, distrib
### Dependency rules
- **`lfx` MUST NOT import `langflow.*` or `langflow-base.*`.** If lfx code needs a service (auth, db, flow lookup), define an interface inside `lfx` and inject the implementation from `langflow`. The repo currently has ~13 upward `from langflow.*` imports inside `src/lfx/src/lfx/components/...` (auth, db, helpers) — these are **known violations**. Do not add more; prefer fixing them.
- **`langflow-base` MAY import `lfx`.** It MUST NOT import vendor-specific component modules from `langflow.components.<vendor>`.
- **`frontend` talks to `langflow` only via HTTP/WebSocket.** No shared filesystem state.
- **`lfx` MUST NOT import `flow.*` or `flow-base.*`.** If lfx code needs a service (auth, db, flow lookup), define an interface inside `lfx` and inject the implementation from `flow`. The repo currently has ~13 upward `from flow.*` imports inside `src/lfx/src/lfx/components/...` (auth, db, helpers) — these are **known violations**. Do not add more; prefer fixing them.
- **`flow-base` MAY import `lfx`.** It MUST NOT import vendor-specific component modules from `flow.components.<vendor>`.
- **`frontend` talks to `flow` only via HTTP/WebSocket.** No shared filesystem state.
## "Where does this code go?" decision tree
@@ -30,7 +30,7 @@ Walk top-down. Stop at the first match.
1. Is it framework-agnostic flow execution, base component classes, or `Component` primitives?
→ `src/lfx/src/lfx/` (`base/` for shared primitives, `components/` for built-ins shipped with lfx).
2. Is it a FastAPI route, auth, db model, alembic migration, or a lifecycle-managed singleton?
→ `src/backend/base/langflow/` (`api/`, `services/X/`, `alembic/versions/`).
→ `src/backend/base/flow/` (`api/`, `services/X/`, `alembic/versions/`).
3. Is it a vendor integration (OpenAI, Pinecone, Notion, …) — a `Component` subclass that wraps a third-party SDK?
→ `src/lfx/src/lfx/components/<category>/` and update its `__init__.py` alphabetically. Never rename the class.
4. Is it UI, state, or icons?
@@ -41,17 +41,17 @@ Walk top-down. Stop at the first match.
→ `services/database/models/` AND `make alembic-revision message="..."` AND apply with `make alembic-upgrade`.
7. Is it a flow JSON schema change?
→ STOP. Existing saved flows must keep loading. Add a version mapping; do not mutate the existing shape. See [CONTRACTS.md](./CONTRACTS.md).
8. Is it shared by both `lfx` and `langflow-base`?
→ `src/lfx/src/lfx/base/`, never `langflow/base/`.
8. Is it shared by both `lfx` and `flow-base`?
→ `src/lfx/src/lfx/base/`, never `flow/base/`.
## Dependency direction — bad/good examples
- **Bad:** `from langflow.services.deps import session_scope` inside `src/lfx/...`.
**Good:** Define `lfx.interfaces.SessionProvider`, accept it as a constructor arg; `langflow` wires the concrete `session_scope` at startup.
- **Bad:** `from langflow.components.openai import ...` inside `langflow-base` core (`api/`, `services/`, `graph/`).
- **Bad:** `from flow.services.deps import session_scope` inside `src/lfx/...`.
**Good:** Define `lfx.interfaces.SessionProvider`, accept it as a constructor arg; `flow` wires the concrete `session_scope` at startup.
- **Bad:** `from flow.components.openai import ...` inside `flow-base` core (`api/`, `services/`, `graph/`).
**Good:** Components are loaded dynamically via the component registry; core code references `Component` only.
- **Bad:** A new `MyHelperService` that's just functions.
**Good:** Utility functions go in `langflow/helpers/` or `lfx/utils/`. A service inherits from `services/base.Service` and is registered via `services/factory.py`.
**Good:** Utility functions go in `flow/helpers/` or `lfx/utils/`. A service inherits from `services/base.Service` and is registered via `services/factory.py`.
## API change protocol
@@ -64,7 +64,7 @@ Walk top-down. Stop at the first match.
A change that touches a request/response shape MUST update three places in the same PR:
1. The pydantic model in `langflow/api/v{1,2}/schemas.py` (or the route's local schema).
1. The pydantic model in `flow/api/v{1,2}/schemas.py` (or the route's local schema).
2. The TypeScript type in `src/frontend/src/types/` consumed by the affected page/store. There is no OpenAPI generator — the types are hand-maintained, so the frontend silently breaks at runtime if you skip this.
3. If the field is persisted: a new alembic revision (`make alembic-revision message=...`) AND a flow-JSON version mapping if the shape lives inside saved flows.
@@ -76,6 +76,6 @@ If you cannot do all three in one PR, do not start.
- **Utility** (`helpers/`, `utils/`, or `lfx/utils/`): pure or near-pure functions. Use when there is no shared state and no lifecycle.
- **Component** (`src/lfx/src/lfx/components/<category>/`): user-visible node in the graph, subclass of `Component`, with `display_name`, `inputs`, `outputs`. Use only when the user must wire it on the canvas. Do not add a Component to expose internal plumbing.
## `lfx/base/` vs `langflow/base/`
## `lfx/base/` vs `flow/base/`
Both exist. Both have `agents/`, `data/`, `models/`, `prompts/`. New shared primitives go in **`src/lfx/src/lfx/base/`**. The `langflow/base/` tree is legacy; do not add to it.
Both exist. Both have `agents/`, `data/`, `models/`, `prompts/`. New shared primitives go in **`src/lfx/src/lfx/base/`**. The `flow/base/` tree is legacy; do not add to it.
+4 -4
View File
@@ -1,8 +1,8 @@
# Component Development
Components are the unit of work in Langflow. They render as nodes on the canvas, persist into flow JSON, and become tools for Agents. Get the contract right and the rest of the system follows; get it wrong and you orphan every saved flow that referenced your component.
Components are the unit of work in Hanzo Flow. They render as nodes on the canvas, persist into flow JSON, and become tools for Agents. Get the contract right and the rest of the system follows; get it wrong and you orphan every saved flow that referenced your component.
Components live in **`src/lfx/src/lfx/components/<category>/`**. The mirror tree under `src/backend/base/langflow/components/` is legacy stubs — do not add files there.
Components live in **`src/lfx/src/lfx/components/<category>/`**. The mirror tree under `src/backend/base/flow/components/` is legacy stubs — do not add files there.
## Before you add a component (decision checklist)
@@ -15,7 +15,7 @@ Stop and check, in order. If any answer is "yes," do not create a new component.
and check the category folder. The Calculator regret (two of them, see `tools/calculator.py` `legacy = True, replacement = ["helpers.CalculatorComponent"]`) is what happens when this step is skipped.
2. **Is this a thin wrapper around an existing tool/SDK that an Agent could call directly via `tool_mode=True`?** If yes, add `tool_mode=True` to the relevant input on the existing component instead of building a new one.
3. **Does it belong in a vendor bundle** (e.g., `openai/`, `anthropic/`, `datastax/`) rather than in generic `tools/` or `helpers/`? Vendor logic goes in vendor folders so bundles can ship/version independently.
4. **Is this an lfx-runtime concern** (graph execution, schema, IO primitives) or a **Langflow-app concern** (auth, DB, tracing)? Components are lfx; never import `langflow.services.*` from a component.
4. **Is this an lfx-runtime concern** (graph execution, schema, IO primitives) or a **Hanzo Flow-app concern** (auth, DB, tracing)? Components are lfx; never import `flow.services.*` from a component.
5. **Does an existing base class cover this category?** Use it:
- LLMs → `LCModelComponent` (see `openai/openai_chat_model.py`)
- Tools → `LCToolComponent` (see `tools/calculator.py`)
@@ -60,7 +60,7 @@ These appear all over the codebase but rarely in old docs.
- **`real_time_refresh=True` + `update_build_config(self, build_config, value, name)`**: dynamic form. Use for mode switches and dependent-field hide/show. Examples: `openai/openai_chat_model.py`, `vectorstores/local_db.py`.
- **`metadata = {"keywords": [...]}`**: extra search terms for the component picker. Example: `data_source/sql_executor.py`.
- **`minimized = True`**: render collapsed by default. Example: `input_output/chat.py`.
- **`documentation = "https://docs.langflow.org/..."`**: deep-link from the node UI. Example: `input_output/chat.py`.
- **`documentation = "https://docs.flow.org/..."`**: deep-link from the node UI. Example: `input_output/chat.py`.
## Placement rules
+7 -7
View File
@@ -12,13 +12,13 @@ These are the surfaces users depend on. Breaking them silently is the most commo
| 4 | Input `name=` and `Output(name=...)` on every component | The component file itself | NEVER rename or remove. Saved flows reference these as keys. Adding new optional inputs is safe; removing or renaming breaks every saved flow that used them. |
| 5 | Output order and `Output.types` | Component `outputs = [...]` list | Reordering changes default selection in old flows. Tightening a type is a breaking change; widening is safe. |
| 6 | Default values for inputs | `default=` / `value=` in input spec | Changing a default silently changes behavior for users who relied on the default. Treat as a breaking change unless the old default was a bug. |
| 7 | Flow JSON schema | `src/backend/base/langflow/initial_setup/starter_projects/*.json` (canonical examples) | Top-level `data.nodes[*].data.node` shape and `data.edges` shape are public. New fields must be optional with defaults. |
| 7 | Flow JSON schema | `src/backend/base/flow/initial_setup/starter_projects/*.json` (canonical examples) | Top-level `data.nodes[*].data.node` shape and `data.edges` shape are public. New fields must be optional with defaults. |
| 8 | Public REST API | `docs/docs/API-Reference/api-flows-run.mdx`, `api-build.mdx`, `api-files.mdx`, `api-projects.mdx`, `api-logs.mdx`, `api-monitor.mdx`, `api-users.mdx`. Endpoints with `include_in_schema=False` are internal. | Documented endpoints are stable. `POST /api/v1/run/{flow_id_or_name}` and `POST /api/v1/webhook/{flow_id_or_name}` are user contracts — payload shape and status codes are frozen. |
| 9 | MCP tool exposure | `src/backend/base/langflow/api/v1/mcp.py`, `mcp_projects.py`. Tool-mode toggled by `Output.tool_mode` / outputs named `component_as_tool`. | Removing `tool_mode=True` from an existing component output, or changing its name, breaks every Agent flow using it as a tool. |
| 9 | MCP tool exposure | `src/backend/base/flow/api/v1/mcp.py`, `mcp_projects.py`. Tool-mode toggled by `Output.tool_mode` / outputs named `component_as_tool`. | Removing `tool_mode=True` from an existing component output, or changing its name, breaks every Agent flow using it as a tool. |
| 10 | `Message` / `Data` / `DataFrame` schema | `src/lfx/src/lfx/schema/message.py` (`text`, `sender`, `sender_name`, `session_id`, `flow_id`, `timestamp`, `properties`, `content_blocks`, `category`, `files`, `error`, `edit`, `duration`, `session_metadata`) | Inter-component wire format. Add fields with defaults only. Renaming or retyping any listed field breaks every running flow. |
| 11 | Environment variables | `LANGFLOW_*` (server) defined in `src/backend/base/langflow/services/settings/base.py` and `feature_flags.py`. `LFX_*` (executor) defined in `src/lfx/src/lfx/services/settings/base.py`, except a few read directly via `os.getenv` (e.g., `LFX_DEV` in `src/lfx/src/lfx/interface/components.py`). | Public deployment contract. Renaming requires deprecation cycle reading both names. |
| 12 | Database schema | `src/backend/base/langflow/services/database/models/` + `alembic/versions/`. | NEVER edit a model without `make alembic-revision`. Never edit a past migration. Custom-component Python source is stored in user DBs — refactoring an import path used by `from langflow.X import Y` breaks loading those rows. |
| 13 | Starter project JSON | `src/backend/base/langflow/initial_setup/starter_projects/*.json` | Each references real components by `name`/`type`. Renaming a component, removing an input, or changing an output type breaks loading. After ANY component change, re-load the affected starter project. |
| 11 | Environment variables | `LANGFLOW_*` (server) defined in `src/backend/base/flow/services/settings/base.py` and `feature_flags.py`. `LFX_*` (executor) defined in `src/lfx/src/lfx/services/settings/base.py`, except a few read directly via `os.getenv` (e.g., `LFX_DEV` in `src/lfx/src/lfx/interface/components.py`). | Public deployment contract. Renaming requires deprecation cycle reading both names. |
| 12 | Database schema | `src/backend/base/flow/services/database/models/` + `alembic/versions/`. | NEVER edit a model without `make alembic-revision`. Never edit a past migration. Custom-component Python source is stored in user DBs — refactoring an import path used by `from flow.X import Y` breaks loading those rows. |
| 13 | Starter project JSON | `src/backend/base/flow/initial_setup/starter_projects/*.json` | Each references real components by `name`/`type`. Renaming a component, removing an input, or changing an output type breaks loading. After ANY component change, re-load the affected starter project. |
| 14 | Webhook payload shape | `POST /api/v1/webhook/{flow_id_or_name}` | External systems POST here. Response status (202 Accepted) and the `dict` body shape are frozen. |
| 15 | Component index | `src/lfx/src/lfx/_assets/component_index.json` | Generated artifact consumed by the frontend. Any field/output addition requires regeneration; CI enforces this on label add. |
@@ -45,13 +45,13 @@ These all look like cleanup. They are user-visible regressions.
- **Reordering `outputs = [a, b]` to `[b, a]`**: old flows with the default selection now route from the wrong output.
- **Tightening `Output(types=["Message", "Data"])` → `["Message"]`**: edges that resolved as `Data` go invalid on load.
- **Changing a `default="gpt-4o-mini"` to `default="gpt-5"`**: silently re-bills users.
- **Moving `langflow/components/foo/bar.py` → `langflow/components/foo2/bar.py`**: custom components stored in user DBs that `from langflow.components.foo.bar import ...` fail on next load. `file_names_mapping` test passes because it only validates listed historical versions, not user code.
- **Moving `flow/components/foo/bar.py` → `flow/components/foo2/bar.py`**: custom components stored in user DBs that `from flow.components.foo.bar import ...` fail on next load. `file_names_mapping` test passes because it only validates listed historical versions, not user code.
- **Dropping `tool_mode=True` from a vector store's `as_dataframe`**: every Agent that called it as a tool now sees the tool disappear.
- **Adding a required field to `Message`**: every queued message in a running deployment fails to deserialize on next read.
- **Renaming a starter project file**: deep links from docs and tutorials 404.
## Why this matters
Langflow flows are **persisted user artifacts** running in production. The system that loads them is forgiving by design: it tolerates new fields, falls back on missing ones, applies type migrations on load. That tolerance is paid for by every contract in the table above. Break one and the system can no longer route around it — the flow stops working.
Hanzo Flow flows are **persisted user artifacts** running in production. The system that loads them is forgiving by design: it tolerates new fields, falls back on missing ones, applies type migrations on load. That tolerance is paid for by every contract in the table above. Break one and the system can no longer route around it — the flow stops working.
Treat this file as a checklist. If your change touches any row, the corresponding rule applies; no exceptions without an explicit deprecation plan.
+4 -4
View File
@@ -2,17 +2,17 @@
Read this file before scoping any non-trivial work. Most off-narrative work comes from skipping it.
Langflow is a **visual flow builder first**. Every change should make sense to someone whose only interface is dragging nodes onto a canvas. Use these principles to scope work; if a proposed change fails one of them, stop and reconsider.
Hanzo Flow is a **visual flow builder first**. Every change should make sense to someone whose only interface is dragging nodes onto a canvas. Use these principles to scope work; if a proposed change fails one of them, stop and reconsider.
## Tenets
1. **Flows are user artifacts, not implementation details.** Flow JSON lives in users' databases and runs in production. Backwards compatibility for components is non-negotiable: never rename a class name, `name` attribute, input name, or output name; never remove an input or output; never tighten an output type; never remove methods from base classes like `LCModelComponent`. To change a component, add the new one alongside, set `legacy=True` + `replacement=[...]` on the old, and update `file_names_mapping` in tests so saved flows still load. See [CONTRACTS.md](./CONTRACTS.md) for the full surface.
2. **Every backend feature must land on the canvas.** If a capability cannot be expressed as a component (or a property of one) that a non-Python user can wire up, it is an SDK feature and belongs in `lfx`, not `langflow-base`. Backend changes that have no visual surface are almost always off-narrative.
2. **Every backend feature must land on the canvas.** If a capability cannot be expressed as a component (or a property of one) that a non-Python user can wire up, it is an SDK feature and belongs in `lfx`, not `flow-base`. Backend changes that have no visual surface are almost always off-narrative.
3. **Components are the unit of work, not endpoints or services.** Before adding a route, store, or service, ask: which component does this serve? If the answer is "none yet," the route is premature. New REST endpoints without a component or UI consumer are off-narrative.
4. **`lfx` is the runtime, `langflow-base` is the platform, `langflow` is the distribution.** Components and the graph engine live in `lfx` (`src/lfx/src/lfx/components/`). API, auth, persistence, and multi-user concerns live in `langflow-base`. The `langflow` package is the integration that ships everything together. New code goes in the lowest layer that can host it. Boundaries are enforced one-way: `langflow` → `langflow-base` → `lfx`. See [ARCHITECTURE.md](./ARCHITECTURE.md).
4. **`lfx` is the runtime, `flow-base` is the platform, `flow` is the distribution.** Components and the graph engine live in `lfx` (`src/lfx/src/lfx/components/`). API, auth, persistence, and multi-user concerns live in `flow-base`. The `flow` package is the integration that ships everything together. New code goes in the lowest layer that can host it. Boundaries are enforced one-way: `flow` → `flow-base` → `lfx`. See [ARCHITECTURE.md](./ARCHITECTURE.md).
5. **Don't add a config flag for something a builder-user would set on a node.** If a setting affects flow behavior, it's a component input. If it affects deployment, it's an env var. Hidden global flags that change component semantics break the visible-data-flow contract.
@@ -24,7 +24,7 @@ Langflow is a **visual flow builder first**. Every change should make sense to s
9. **The Playground is the test harness builder-users see.** A component is "done" when it works end-to-end in a flow on the canvas, not when its unit test passes. Use the Graph test pattern (build, `.set()`, `async_start`, validate) before claiming a feature works.
10. **Two audiences, one product: visual builders and Python devs.** When their needs conflict, the visual builder wins for `langflow-base` features and the Python dev wins for `lfx` SDK features. Don't compromise the canvas to make the SDK prettier, and don't compromise the SDK to make the canvas easier.
10. **Two audiences, one product: visual builders and Python devs.** When their needs conflict, the visual builder wins for `flow-base` features and the Python dev wins for `lfx` SDK features. Don't compromise the canvas to make the SDK prettier, and don't compromise the SDK to make the canvas easier.
11. **It is not a fix if you didn't have evidence of the change fixing something.** Adding error handling, retries, type widening, or skipping a flaky test does not constitute a fix. Reproduce the failure, demonstrate the fix removes it, then ship. See [ANTI-PATTERNS.md](./ANTI-PATTERNS.md).
+2 -2
View File
@@ -41,11 +41,11 @@ Every subclass provides three fixtures:
1. **`component_class`** — the component class under test.
2. **`default_kwargs`** — dict of kwargs to instantiate the component (can be empty).
3. **`file_names_mapping`** — list of `VersionComponentMapping` entries mapping each historical Langflow version (from `src/backend/tests/constants.py::SUPPORTED_VERSIONS`) to module/file names. Use `DID_NOT_EXIST` for versions before the component was added.
3. **`file_names_mapping`** — list of `VersionComponentMapping` entries mapping each historical Hanzo Flow version (from `src/backend/tests/constants.py::SUPPORTED_VERSIONS`) to module/file names. Use `DID_NOT_EXIST` for versions before the component was added.
```python
from tests.base import ComponentTestBaseWithClient, VersionComponentMapping, DID_NOT_EXIST
from langflow.components.my_namespace import MyComponent
from flow.components.my_namespace import MyComponent
class TestMyComponent(ComponentTestBaseWithClient):
@pytest.fixture
+1 -1
View File
@@ -1,6 +1,6 @@
# API Examples (Local Test Harness)
Run all API example suites against a local Langflow server:
Run all API example suites against a local Hanzo Flow server:
```bash
make api_examples_local
+8 -8
View File
@@ -27,16 +27,16 @@ import exampleJavascriptApiBuildOverrideFlowParameters from '!!raw-loader!@site/
:::info
The `/build` endpoints are used by Langflow's frontend visual editor code.
These endpoints are part of the internal Langflow codebase.
The `/build` endpoints are used by Hanzo Flow's frontend visual editor code.
These endpoints are part of the internal Hanzo Flow codebase.
Don't use these endpoints to run flows in applications that use your Langflow flows.
Don't use these endpoints to run flows in applications that use your Hanzo Flow flows.
To run flows in your apps, see [Flow trigger endpoints](/api-flows-run).
:::
The `/build` endpoints support Langflow's frontend code for building flows in the Langflow visual editor.
The `/build` endpoints support Hanzo Flow's frontend code for building flows in the Hanzo Flow visual editor.
You can use these endpoints to build vertices and flows, as well as execute flows with streaming event responses.
You might need to use or understand these endpoints when contributing to the Langflow codebase.
You might need to use or understand these endpoints when contributing to the Hanzo Flow codebase.
## Build flow and stream events
@@ -132,8 +132,8 @@ To disable streaming and get all events at once, set `?stream=false`.
| inputs | object | Optional. Input values for flow components. |
| data | object | Optional. Flow data to override stored configuration. |
| files | array[string] | Optional. List of file paths to use. |
| start_component_id | string | Optional. ID of the component where the execution should start. Component `id` values can be found in [Langflow JSON files](/concepts-flows-import#langflow-json-file-contents) |
| stop_component_id | string | Optional. ID of the component where the execution should stop. Component `id` values can be found in [Langflow JSON files](/concepts-flows-import#langflow-json-file-contents).|
| start_component_id | string | Optional. ID of the component where the execution should start. Component `id` values can be found in [Hanzo Flow JSON files](/concepts-flows-import#flow-json-file-contents) |
| stop_component_id | string | Optional. ID of the component where the execution should stop. Component `id` values can be found in [Hanzo Flow JSON files](/concepts-flows-import#flow-json-file-contents).|
| log_builds | Boolean | Whether to record build logs. Default: Enabled (`true`). |
### Set start and stop points
@@ -163,7 +163,7 @@ The following example stops flow execution at an **OpenAI** component:
### Override flow parameters
The `/build` endpoint also accepts inputs for `data` directly, instead of using the values stored in the Langflow database.
The `/build` endpoint also accepts inputs for `data` directly, instead of using the values stored in the Hanzo Flow database.
This is useful for running flows without having to pass custom values through the visual editor.
<Tabs>
+11 -11
View File
@@ -63,9 +63,9 @@ import exampleJavascriptApiFilesDeleteAllFilesV2 from '!!raw-loader!@site/docs/A
Use the `/files` endpoints to move files between your local machine and Langflow.
Use the `/files` endpoints to move files between your local machine and Hanzo Flow.
All `/files` endpoints (both `/v1/files` and `/v2/files`) require authentication with a Langflow API key.
All `/files` endpoints (both `/v1/files` and `/v2/files`) require authentication with a Hanzo Flow API key.
You can only access files that belong to your own user account, even as a superuser.
## Differences between `/v1/files` and `/v2/files`
@@ -76,8 +76,8 @@ There are two versions of the `/files` endpoints.
- `/v2` files are organized by `user_id` instead of `flow_id`.
This means files are owned by users, and they aren't attached to specific flows.
You can upload a file to Langflow one time, and use it with multiple flows.
- `/v2` files are tracked in the Langflow database.
You can upload a file to Hanzo Flow one time, and use it with multiple flows.
- `/v2` files are tracked in the Hanzo Flow database.
- `/v2` supports bulk upload and delete.
- `/v2` responses contain more descriptive metadata.
@@ -86,7 +86,7 @@ To send image files to your flows through the API, use [Upload image files (v1)]
## Files/V1 endpoints
Use the `/files` endpoints to move files between your local machine and Langflow.
Use the `/files` endpoints to move files between your local machine and Hanzo Flow.
### Upload file (v1)
@@ -123,7 +123,7 @@ Not all file types are supported.
### Upload image files (v1)
Send image files to Langflow to use them in flows.
Send image files to Hanzo Flow to use them in flows.
The default file limit is 1024 MB.
To change this limit, set the `LANGFLOW_MAX_FILE_SIZE_UPLOAD` [environment variable](/environment-variables).
@@ -148,7 +148,7 @@ To change this limit, set the `LANGFLOW_MAX_FILE_SIZE_UPLOAD` [environment varia
</TabItem>
</Tabs>
A successful request returns the `file_path` for the image in the Langflow file management system in the format `FLOW_ID/TIMESTAMP_FILENAME.TYPE`.
A successful request returns the `file_path` for the image in the Hanzo Flow file management system in the format `FLOW_ID/TIMESTAMP_FILENAME.TYPE`.
For example:
```json
@@ -275,10 +275,10 @@ Delete a specific file from a flow.
## Files/V2 endpoints
Use the `/files` endpoints to move files between your local machine and Langflow.
Use the `/files` endpoints to move files between your local machine and Hanzo Flow.
The `/v2/files` endpoints can be authenticated by an API key or JWT.
To create a Langflow API key and export it as an environment variable, see [Get started with the Langflow API](/api-reference-api-examples).
To create a Hanzo Flow API key and export it as an environment variable, see [Get started with the Hanzo Flow API](/api-reference-api-examples).
### Upload file (v2)
@@ -353,7 +353,7 @@ The `/v2/files` endpoint can't send image files to flows.
To send image files to your flows through the API, see [Upload image files (v1)](#upload-image-files-v1).
:::
This endpoint uploads files to your Langflow server's file management system.
This endpoint uploads files to your Hanzo Flow server's file management system.
To use an uploaded file in a flow, send the file path to a flow with a [**Read File** component](/read-file).
The default file limit is 1024 MB. To configure this value, change the `LANGFLOW_MAX_FILE_SIZE_UPLOAD` [environment variable](/environment-variables).
@@ -394,7 +394,7 @@ The default file limit is 1024 MB. To configure this value, change the `LANGFLOW
```
2. To use this file in your flow, add a **Read File** component to your flow.
This component loads files into flows from your local machine or Langflow file management.
This component loads files into flows from your local machine or Hanzo Flow file management.
3. Run the flow, passing the `path` to the `Read-File` component in the `tweaks` object:
+5 -5
View File
@@ -33,7 +33,7 @@ To create, read, update, and delete flows, see [Flow management endpoints](/api-
## Run flow
:::tip
Langflow automatically generates Python, JavaScript, and curl code snippets for the `/v1/run/$FLOW_ID` endpoint for all flows.
Hanzo Flow automatically generates Python, JavaScript, and curl code snippets for the `/v1/run/$FLOW_ID` endpoint for all flows.
For more information, see [Generate API code snippets](/concepts-publish#generate-api-code-snippets).
:::
@@ -102,7 +102,7 @@ The following example illustrates a response from a Basic Prompting flow:
</details>
If you are parsing the response in an application, you most likely need to extract the relevant content from the response, rather than pass the entire response back to the user.
For an example of a script that extracts data from a Langflow API response, see the [Quickstart](/get-started-quickstart).
For an example of a script that extracts data from a Hanzo Flow API response, see the [Quickstart](/get-started-quickstart).
### Stream LLM token responses
@@ -165,7 +165,7 @@ The following example is truncated to illustrate a series of `token` events as w
|--------|------|---------|
| Content-Type | Required. Specifies the JSON format. | "application/json" |
| accept | Optional. Specifies the response format. Defaults to JSON if not specified. | "application/json" |
| x-api-key | Required. Your Langflow API key for authentication. Can be passed as a header or query parameter. | "sk-..." |
| x-api-key | Required. Your Hanzo Flow API key for authentication. Can be passed as a header or query parameter. | "sk-..." |
| `X-LANGFLOW-GLOBAL-VAR-*` | Optional. Pass global variables to the flow. Variable names are automatically converted to uppercase. These variables take precedence over OS environment variables and are only available during this specific request execution. | `"X-LANGFLOW-GLOBAL-VAR-API_KEY: sk-..."` |
### Run endpoint parameters
@@ -209,7 +209,7 @@ Variables passed in headers take precedence over OS environment variables. If a
Variable names are automatically converted to uppercase. For example, `X-LANGFLOW-GLOBAL-VAR-api-key` becomes `API_KEY` in your flow.
You don't need to create these variables in Langflow's Global Variables section first. Pass any variable name using this header format.
You don't need to create these variables in Hanzo Flow's Global Variables section first. Pass any variable name using this header format.
<Tabs>
<TabItem value="Python" label="Python" default>
@@ -229,7 +229,7 @@ You don't need to create these variables in Langflow's Global Variables section
</TabItem>
</Tabs>
If your flow components reference variables that aren't provided in headers or your Langflow database, the flow fails by default. To avoid this, you can set `LANGFLOW_FALLBACK_TO_ENV_VAR=True` in your `.env` file, which allows the flow to use values from OS environment variables if they aren't otherwise specified.
If your flow components reference variables that aren't provided in headers or your Hanzo Flow database, the flow fails by default. To avoid this, you can set `LANGFLOW_FALLBACK_TO_ENV_VAR=True` in your `.env` file, which allows the flow to use values from OS environment variables if they aren't otherwise specified.
## Webhook run flow
+3 -3
View File
@@ -45,7 +45,7 @@ import exampleJavascriptApiFlowsImportFlows from '!!raw-loader!@site/docs/API-Re
Use the `/flows` endpoint to create, read, update, and delete flows.
If you want to use the Langflow API to run a flow, see [Flow trigger endpoints](/api-flows-run).
If you want to use the Hanzo Flow API to run a flow, see [Flow trigger endpoints](/api-flows-run).
## Create flow
@@ -257,7 +257,7 @@ Deletes a specific flow by its ID.
Exports specified flows to a ZIP file.
This endpoint downloads a ZIP file containing [Langflow JSON files](/concepts-flows-import#langflow-json-file-contents) for each flow ID listed in the request body.
This endpoint downloads a ZIP file containing [Hanzo Flow JSON files](/concepts-flows-import#flow-json-file-contents) for each flow ID listed in the request body.
<Tabs>
<TabItem value="Python" label="Python" default>
@@ -286,7 +286,7 @@ This endpoint downloads a ZIP file containing [Langflow JSON files](/concepts-fl
## Import flows
Imports flows by uploading a [Langflow-compatible JSON file](/concepts-flows-import#langflow-json-file-contents).
Imports flows by uploading a [Hanzo Flow-compatible JSON file](/concepts-flows-import#flow-json-file-contents).
To specify a target project for the flow, include the query parameter `folder_id`.
The target `folder_id` must already exist before uploading a flow. Call the [/api/v1/projects/](/api-projects#read-projects) endpoint for a list of available folders and projects.
+3 -3
View File
@@ -16,13 +16,13 @@ import exampleJavascriptApiLogsRetrieveLogsWithOptionalParameters from '!!raw-lo
Retrieve logs for your Langflow flows and server.
Retrieve logs for your Hanzo Flow flows and server.
## Enable log retrieval
The `/logs` endpoint requires log retrieval to be enabled in your Langflow instance.
The `/logs` endpoint requires log retrieval to be enabled in your Hanzo Flow instance.
To enable log retrieval, set the following [environment variables](/environment-variables) in your Langflow `.env` file, and then start Langflow with `uv run langflow run --env-file .env`:
To enable log retrieval, set the following [environment variables](/environment-variables) in your Hanzo Flow `.env` file, and then start Hanzo Flow with `uv run flow run --env-file .env`:
```text
LANGFLOW_ENABLE_LOG_RETRIEVAL=True
+8 -8
View File
@@ -47,24 +47,24 @@ import exampleJavascriptApiMonitorGetTransactions from '!!raw-loader!@site/docs/
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
The `/monitor` endpoints are for internal Langflow functionality, primarily related to running flows in the **Playground**, storing chat history, and generating flow logs.
The `/monitor` endpoints are for internal Hanzo Flow functionality, primarily related to running flows in the **Playground**, storing chat history, and generating flow logs.
This information is primarily for those who are building custom components or contributing to the Langflow codebase in a way that requires calling or understanding these endpoints.
This information is primarily for those who are building custom components or contributing to the Hanzo Flow codebase in a way that requires calling or understanding these endpoints.
For typical application development with Langflow, there are more appropriate options for monitoring, debugging, and memory management.
For typical application development with Hanzo Flow, there are more appropriate options for monitoring, debugging, and memory management.
For more information, see the following:
* [Logs](/logging): Langflow log storage locations, customization options, and where to view logs in the visual editor
* [Logs](/logging): Hanzo Flow log storage locations, customization options, and where to view logs in the visual editor
* [Test flows in the Playground](/concepts-playground): Run flows and inspect message history
* [Memory management options](/memory): Langflow storage locations and options, including the database, cache, and chat history
* [Memory management options](/memory): Hanzo Flow storage locations and options, including the database, cache, and chat history
## Vertex builds
The Vertex build endpoints (`/monitor/builds`) are exclusively for **Playground** functionality.
When you run a flow in the **Playground**, Langflow calls the `/build/$FLOW_ID/flow` endpoint in [chat.py](https://github.com/langflow-ai/langflow/blob/main/src/backend/base/langflow/api/v1/chat.py#L130). This call retrieves the flow data, builds a graph, and executes the graph. As each component (or node) is executed, the `build_vertex` function calls `build_and_run`, which may call the individual components' `def_build` method, if it exists. If a component doesn't have a `def_build` function, the build still returns a component.
When you run a flow in the **Playground**, Hanzo Flow calls the `/build/$FLOW_ID/flow` endpoint in [chat.py](https://github.com/hanzoai/flow/blob/main/src/backend/base/flow/api/v1/chat.py#L130). This call retrieves the flow data, builds a graph, and executes the graph. As each component (or node) is executed, the `build_vertex` function calls `build_and_run`, which may call the individual components' `def_build` method, if it exists. If a component doesn't have a `def_build` function, the build still returns a component.
The `build` function allows components to execute logic at runtime. For example, the [**Recursive Character Text Splitter** component](https://github.com/langflow-ai/langflow/blob/main/src/lfx/src/lfx/components/langchain_utilities/recursive_character.py) is a child of the `LCTextSplitterComponent` class. When text needs to be processed, the parent class's `build` method is called, which creates a `RecursiveCharacterTextSplitter` object and uses it to split the text according to the defined parameters. The split text is then passed on to the next component. This all occurs when the component is built.
The `build` function allows components to execute logic at runtime. For example, the [**Recursive Character Text Splitter** component](https://github.com/hanzoai/flow/blob/main/src/lfx/src/lfx/components/langchain_utilities/recursive_character.py) is a child of the `LCTextSplitterComponent` class. When text needs to be processed, the parent class's `build` method is called, which creates a `RecursiveCharacterTextSplitter` object and uses it to split the text according to the defined parameters. The split text is then passed on to the next component. This all occurs when the component is built.
### Get Vertex builds
@@ -126,7 +126,7 @@ Delete Vertex builds for a specific flow.
## Messages endpoints
The `/monitor/messages` endpoints store, retrieve, edit, and delete records in the message table in [`langflow.db`](/memory)
The `/monitor/messages` endpoints store, retrieve, edit, and delete records in the message table in [`flow.db`](/memory)
Typically, these are called implicitly when running flows that produce message history, or when inspecting and modifying **Playground** memories.
### Get messages
@@ -40,7 +40,7 @@ import exampleJavascriptApiOpenaiResponsesTokenUsageTracking from '!!raw-loader!
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
Langflow includes an endpoint that is compatible with the [OpenAI Responses API](https://platform.openai.com/docs/api-reference/responses).
Hanzo Flow includes an endpoint that is compatible with the [OpenAI Responses API](https://platform.openai.com/docs/api-reference/responses).
It is available at `POST /api/v1/responses`.
This endpoint allows you to use existing OpenAI client libraries with minimal code changes.
@@ -49,7 +49,7 @@ You can find Flow IDs in the code snippets on the [**API access** pane](/concept
## Prerequisites
To be compatible with Langflow's OpenAI Responses API endpoint, your flow and request must adhere to the following requirements:
To be compatible with Hanzo Flow's OpenAI Responses API endpoint, your flow and request must adhere to the following requirements:
- **Chat Input**: Your flow must contain a **Chat Input** component.
Flows without this component return an error when passed to this endpoint.
@@ -62,8 +62,8 @@ For more information, see [API keys and authentication](/api-keys-and-authentica
### Additional configuration for OpenAI client libraries
This endpoint is compatible with OpenAI's API, but requires special configuration when using OpenAI client libraries.
Langflow uses `x-api-key` headers for authentication, while OpenAI uses `Authorization: Bearer` headers.
When sending requests to Langflow with OpenAI client libraries, you must configure custom headers and include an `api_key` configuration.
Hanzo Flow uses `x-api-key` headers for authentication, while OpenAI uses `Authorization: Bearer` headers.
When sending requests to Hanzo Flow with OpenAI client libraries, you must configure custom headers and include an `api_key` configuration.
The `api_key` parameter can have any value, such as `"dummy-api-key"` in the client examples, as the actual authentication is handled through the `default_headers` configuration.
In the following examples, replace the values for `LANGFLOW_SERVER_URL`, `LANGFLOW_API_KEY`, and `FLOW_ID` with values from your deployment.
@@ -124,7 +124,7 @@ If you need these in a different format or want a downloadable calendar, let me
| Header | Required | Description | Example |
|--------|----------|-------------|---------|
| `x-api-key` | Yes | Your Langflow API key for authentication | `"sk-..."` |
| `x-api-key` | Yes | Your Hanzo Flow API key for authentication | `"sk-..."` |
| `Content-Type` | Yes | Specifies the JSON format | `"application/json"` |
| `X-LANGFLOW-GLOBAL-VAR-*` | No | Global variables for the flow | `"X-LANGFLOW-GLOBAL-VAR-API_KEY: sk-..."` For more, see [Pass global variables to your flows in headers](#global-var). |
@@ -182,7 +182,7 @@ If you need these in a different format or want a downloadable calendar, let me
### Response body
The response contains fields that Langflow sets dynamically and fields that use OpenAI-compatible defaults.
The response contains fields that Hanzo Flow sets dynamically and fields that use OpenAI-compatible defaults.
The OpenAI-compatible default values shown above are currently fixed and cannot be modified via the request.
They are included to maintain API compatibility and provide a consistent response format.
@@ -190,7 +190,7 @@ They are included to maintain API compatibility and provide a consistent respons
For your requests, you will only be setting the dynamic fields.
The default values are documented here for completeness and to show the full response structure.
Fields set dynamically by Langflow:
Fields set dynamically by Hanzo Flow:
| Field | Type | Description |
|-------|------|-------------|
@@ -456,7 +456,7 @@ For example:
Variables passed with `X-LANGFLOW-GLOBAL-VAR-{VARIABLE_NAME}` are always available to your flow, regardless of whether they exist in the database.
If your flow components reference variables that aren't provided in headers or your Langflow database, the flow fails by default.
If your flow components reference variables that aren't provided in headers or your Hanzo Flow database, the flow fails by default.
To avoid this, you can set the `FALLBACK_TO_ENV_VARS` environment variable is `true`, which allows the flow to use values from the `.env` file if they aren't otherwise specified.
+3 -3
View File
@@ -37,11 +37,11 @@ import exampleJavascriptApiProjectsImportAProject from '!!raw-loader!@site/docs/
Use the `/projects` endpoint to create, read, update, and delete [Langflow projects](/concepts-flows#projects).
Use the `/projects` endpoint to create, read, update, and delete [Hanzo Flow projects](/concepts-flows#projects).
## Read projects
Get a list of Langflow projects, including project IDs, names, and descriptions.
Get a list of Hanzo Flow projects, including project IDs, names, and descriptions.
<Tabs>
<TabItem value="Python" label="Python" default>
@@ -238,7 +238,7 @@ The `--output` flag is optional.
## Import a project
Import a project and its flows by uploading a Langflow project zip file:
Import a project and its flows by uploading a Hanzo Flow project zip file:
<Tabs>
<TabItem value="Python" label="Python" default>
@@ -1,9 +1,9 @@
---
title: Get started with the Langflow API
title: Get started with the Hanzo Flow API
slug: /api-reference-api-examples
---
import CodeSnippet from '@site/src/components/CodeSnippet';
import exampleApiReferenceApiExamplesFormLangflowApiRequests from '!!raw-loader!@site/docs/API-Reference/curl-examples/api-reference-api-examples/form-langflow-api-requests.sh';
import exampleApiReferenceApiExamplesFormLangflowApiRequests from '!!raw-loader!@site/docs/API-Reference/curl-examples/api-reference-api-examples/form-flow-api-requests.sh';
import exampleApiReferenceApiExamplesSetEnvironmentVariables from '!!raw-loader!@site/docs/API-Reference/curl-examples/api-reference-api-examples/set-environment-variables.sh';
import exampleApiReferenceApiExamplesHealthCheck from '!!raw-loader!@site/docs/API-Reference/curl-examples/api-reference-api-examples/health-check.sh';
import resultApiReferenceApiExamplesResultHealthCheck from '!!raw-loader!@site/docs/API-Reference/curl-examples/api-reference-api-examples/result-health-check.json';
@@ -12,8 +12,8 @@ import resultApiReferenceApiExamplesResultGetVersion from '!!raw-loader!@site/do
import exampleApiReferenceApiExamplesGetConfiguration from '!!raw-loader!@site/docs/API-Reference/curl-examples/api-reference-api-examples/get-configuration.sh';
import resultApiReferenceApiExamplesResultGetConfiguration from '!!raw-loader!@site/docs/API-Reference/curl-examples/api-reference-api-examples/result-get-configuration.json';
import exampleApiReferenceApiExamplesGetAllComponents from '!!raw-loader!@site/docs/API-Reference/curl-examples/api-reference-api-examples/get-all-components.sh';
import examplePythonApiReferenceApiExamplesFormLangflowApiRequests from '!!raw-loader!@site/docs/API-Reference/python-examples/api-reference-api-examples/form-langflow-api-requests.py';
import exampleJavascriptApiReferenceApiExamplesFormLangflowApiRequests from '!!raw-loader!@site/docs/API-Reference/javascript-examples/api-reference-api-examples/form-langflow-api-requests.js';
import examplePythonApiReferenceApiExamplesFormLangflowApiRequests from '!!raw-loader!@site/docs/API-Reference/python-examples/api-reference-api-examples/form-flow-api-requests.py';
import exampleJavascriptApiReferenceApiExamplesFormLangflowApiRequests from '!!raw-loader!@site/docs/API-Reference/javascript-examples/api-reference-api-examples/form-flow-api-requests.js';
import examplePythonApiReferenceApiExamplesHealthCheck from '!!raw-loader!@site/docs/API-Reference/python-examples/api-reference-api-examples/health-check.py';
import exampleJavascriptApiReferenceApiExamplesHealthCheck from '!!raw-loader!@site/docs/API-Reference/javascript-examples/api-reference-api-examples/health-check.js';
import examplePythonApiReferenceApiExamplesGetVersion from '!!raw-loader!@site/docs/API-Reference/python-examples/api-reference-api-examples/get-version.py';
@@ -28,27 +28,27 @@ import exampleJavascriptApiReferenceApiExamplesGetAllComponents from '!!raw-load
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
You can use the Langflow API for programmatic interactions with Langflow, such as the following:
You can use the Hanzo Flow API for programmatic interactions with Hanzo Flow, such as the following:
* Create and edit flows, including file management for flows.
* Develop applications that use your flows.
* Develop custom components.
* Build Langflow as a dependency of a larger application, codebase, or service.
* Contribute to the overall Langflow codebase.
* Build Hanzo Flow as a dependency of a larger application, codebase, or service.
* Contribute to the overall Hanzo Flow codebase.
To view and test all available endpoints, you can access the Langflow API's OpenAPI specification at your Langflow deployment's `/docs` endpoint, such as `http://localhost:7860/docs`.
To view and test all available endpoints, you can access the Hanzo Flow API's OpenAPI specification at your Hanzo Flow deployment's `/docs` endpoint, such as `http://localhost:7860/docs`.
:::tip Try it
For an example of the Langflow API in a script, see the [Langflow quickstart](/get-started-quickstart).
For an example of the Hanzo Flow API in a script, see the [Hanzo Flow quickstart](/get-started-quickstart).
The quickstart demonstrates how to get automatically generated code snippets for your flows, use a script to run a flow, and extract data from the Langfow API response.
:::
## Form Langflow API requests
## Form Hanzo Flow API requests
While individual options vary by endpoint, all Langflow API requests share some commonalities, like a URL, method, parameters, and authentication.
While individual options vary by endpoint, all Hanzo Flow API requests share some commonalities, like a URL, method, parameters, and authentication.
As an example of a Langflow API request, the following curl command calls the `/v1/run` endpoint, and it passes a runtime override (`tweaks`) to the flow's **Chat Output** component:
As an example of a Hanzo Flow API request, the following curl command calls the `/v1/run` endpoint, and it passes a runtime override (`tweaks`) to the flow's **Chat Output** component:
<Tabs>
<TabItem value="Python" label="Python" default>
@@ -70,11 +70,11 @@ As an example of a Langflow API request, the following curl command calls the `/
### Base URL
By default, local deployments serve the Langflow API at `http://localhost:7860/api`.
By default, local deployments serve the Hanzo Flow API at `http://localhost:7860/api`.
Remotely hosted Langflow deployments are available at the domain set by the hosting service, such as `http://IP_OR_DNS/api` or `http://IP_OR_DNS:LANGFLOW_PORT/api`.
Remotely hosted Hanzo Flow deployments are available at the domain set by the hosting service, such as `http://IP_OR_DNS/api` or `http://IP_OR_DNS:LANGFLOW_PORT/api`.
You can configure the Langflow port number in the `LANGFLOW_PORT` [environment variable](/environment-variables).
You can configure the Hanzo Flow port number in the `LANGFLOW_PORT` [environment variable](/environment-variables).
* `https://UUID.ngrok.app/api`
* `http://IP_OR_DNS/api`
@@ -82,7 +82,7 @@ You can configure the Langflow port number in the `LANGFLOW_PORT` [environment v
### Authentication
In Langflow versions 1.5 and later, most API endpoints require authentication with a Langflow API key in either an `x-api-key` header or query parameter.
In Hanzo Flow versions 1.5 and later, most API endpoints require authentication with a Hanzo Flow API key in either an `x-api-key` header or query parameter.
For more information, see [API keys and authentication](/api-keys-and-authentication).
As with any API, follow industry best practices for storing and referencing sensitive credentials.
@@ -90,7 +90,7 @@ For example, you can [set environment variables](#set-environment-variables) for
### Methods, paths, and parameters
Langflow API requests use various methods, paths, path parameters, query parameters, and body parameters.
Hanzo Flow API requests use various methods, paths, path parameters, query parameters, and body parameters.
The specific requirements and options depend on the endpoint that you want to call.
For example, to create a flow, you pass a JSON-formatted flow definition to `POST /v1/flows`.
@@ -98,7 +98,7 @@ Then, to run your flow, you call `POST /v1/run/$FLOW_ID` with optional run param
### API versions
The Langflow API serves `/v1` and `/v2` endpoints.
The Hanzo Flow API serves `/v1` and `/v2` endpoints.
Some endpoints only exist under a single version and some exist under both the `/v1` and `/v2` versions.
@@ -114,17 +114,17 @@ For example:
<CodeSnippet source={exampleApiReferenceApiExamplesSetEnvironmentVariables} language="bash" />
Commonly used values in Langflow API requests include your [Langflow server URL](#base-url), [Langflow API keys](#authentication), flow IDs, and [project IDs](/api-projects#read-projects).
Commonly used values in Hanzo Flow API requests include your [Hanzo Flow server URL](#base-url), [Hanzo Flow API keys](#authentication), flow IDs, and [project IDs](/api-projects#read-projects).
You can retrieve flow IDs from the [**API access** pane](/concepts-publish#api-access), in a flow's URL, and with [`GET /flows`](/api-flows#read-flows).
## Try some Langflow API requests
## Try some Hanzo Flow API requests
Once you have your Langflow server URL, try calling these endpoints that return Langflow metadata.
Once you have your Hanzo Flow server URL, try calling these endpoints that return Hanzo Flow metadata.
### Health check
Returns the health status of the Langflow database and chat services:
Returns the health status of the Hanzo Flow database and chat services:
<Tabs>
<TabItem value="Python" label="Python" default>
@@ -151,12 +151,12 @@ Returns the health status of the Langflow database and chat services:
</details>
Langflow provides an additional `GET /health` endpoint.
This endpoint is served by uvicorn before Langflow is fully initialized, so it's not reliable for checking Langflow service health.
Hanzo Flow provides an additional `GET /health` endpoint.
This endpoint is served by uvicorn before Hanzo Flow is fully initialized, so it's not reliable for checking Hanzo Flow service health.
### Get version
Returns the current Langflow API version:
Returns the current Hanzo Flow API version:
<Tabs>
<TabItem value="Python" label="Python" default>
@@ -185,8 +185,8 @@ Returns the current Langflow API version:
### Get configuration
Returns configuration details for your Langflow deployment.
Requires a [Langflow API key](/api-keys-and-authentication).
Returns configuration details for your Hanzo Flow deployment.
Requires a [Hanzo Flow API key](/api-keys-and-authentication).
<Tabs>
<TabItem value="Python" label="Python" default>
@@ -215,8 +215,8 @@ Requires a [Langflow API key](/api-keys-and-authentication).
### Get all components
Returns a dictionary of all Langflow components.
Requires a [Langflow API key](/api-keys-and-authentication).
Returns a dictionary of all Hanzo Flow components.
Requires a [Hanzo Flow API key](/api-keys-and-authentication).
<Tabs>
<TabItem value="Python" label="Python" default>
@@ -238,9 +238,9 @@ Requires a [Langflow API key](/api-keys-and-authentication).
## Available endpoints
Because you can run Langflow as either an IDE (frontend and backend) or a runtime (headless, backend-only), it serves endpoints that support frontend and backend operations.
Many endpoints are for orchestration between the frontend and backend, reading and writing to the Langflow database, or enabling frontend functionality, like the **Playground**.
Unless you are contributing to the Langflow codebase, you won't directly call most of the Langflow endpoints.
Because you can run Hanzo Flow as either an IDE (frontend and backend) or a runtime (headless, backend-only), it serves endpoints that support frontend and backend operations.
Many endpoints are for orchestration between the frontend and backend, reading and writing to the Hanzo Flow database, or enabling frontend functionality, like the **Playground**.
Unless you are contributing to the Hanzo Flow codebase, you won't directly call most of the Hanzo Flow endpoints.
For application development, the most commonly used endpoints are the `/run` and `/webhook` [flow trigger endpoints](/api-flows-run).
For some use cases, you might use some other endpoints, such as the `/files` endpoints to use files in flows.
@@ -250,7 +250,7 @@ To help you explore the available endpoints, the following lists are sorted by p
<Tabs>
<TabItem value="Application development" label="Application development" default>
The following endpoints are useful for developing applications with Langflow and administering Langflow deployments with one or more users.
The following endpoints are useful for developing applications with Hanzo Flow and administering Hanzo Flow deployments with one or more users.
You will most often use the flow trigger endpoints.
Other endpoints are helpful for specific use cases, such as administration and flow management in runtime deployments that don't have a visual editor.
@@ -263,7 +263,7 @@ Other endpoints are helpful for specific use cases, such as administration and f
* POST `/v1/responses`: Execute flows using an OpenAI-compatible request format.
* Deployment details:
* GET `/v1/version`: Return Langflow version. See [Get version](/api-reference-api-examples#get-version).
* GET `/v1/version`: Return Hanzo Flow version. See [Get version](/api-reference-api-examples#get-version).
* GET `/v1/config`: Return deployment configuration. See [Get configuration](/api-reference-api-examples#get-configuration).
* GET `/health_check`: Health check endpoint that validates database and chat service connectivity. Returns 500 status if any service is unavailable.
@@ -323,8 +323,8 @@ Other endpoints are helpful for specific use cases, such as administration and f
* PATCH `/v1/users/{user_id}/reset-password`: Reset own password.
* DELETE `/v1/users/{user_id}`: Delete a user (cannot delete yourself).
* Custom components: You might use these endpoints when developing custom Langflow components for your own use or to share with the Langflow community:
* GET `/v1/all`: Return all available Langflow component types. See [Get all components](/api-reference-api-examples#get-all-components).
* Custom components: You might use these endpoints when developing custom Hanzo Flow components for your own use or to share with the Hanzo Flow community:
* GET `/v1/all`: Return all available Hanzo Flow component types. See [Get all components](/api-reference-api-examples#get-all-components).
* POST `/v1/custom_component`: Build a custom component from code and return its node.
* POST `/v1/custom_component/update`: Update an existing custom component's build config and outputs.
* POST `/v1/validate/code`: Validate a Python code snippet for a custom component.
@@ -333,11 +333,11 @@ Other endpoints are helpful for specific use cases, such as administration and f
</TabItem>
<TabItem value="Codebase contribution" label="Codebase development">
The following endpoints are most often used when contributing to the Langflow codebase, and you need to understand or call endpoints that support frontend-to-backend orchestration or other internal functionality.
The following endpoints are most often used when contributing to the Hanzo Flow codebase, and you need to understand or call endpoints that support frontend-to-backend orchestration or other internal functionality.
* Base (metadata):
* GET `/v1/all`: Return all available Langflow component types. See [Get all components](/api-reference-api-examples#get-all-components).
* GET `/v1/version`: Return Langflow version. See [Get version](/api-reference-api-examples#get-version).
* GET `/v1/all`: Return all available Hanzo Flow component types. See [Get all components](/api-reference-api-examples#get-all-components).
* GET `/v1/version`: Return Hanzo Flow version. See [Get version](/api-reference-api-examples#get-version).
* GET `/v1/config`: Return deployment configuration. See [Get configuration](/api-reference-api-examples#get-configuration).
* GET `/v1/starter-projects/`: Return a list of templates.
@@ -378,9 +378,9 @@ The following endpoints are most often used when contributing to the Langflow co
* WS `/v1/voice/ws/flow_tts/{flow_id}/{session_id}`: Same as above with explicit session ID.
* GET `/v1/voice/elevenlabs/voice_ids`: List available ElevenLabs voice IDs for the user.
* MCP servers: The following endpoints are for managing Langflow MCP servers and MCP server connections.
They aren't typically called directly; instead, they are used to drive internal functionality in the Langflow frontend and when running flows that call MCP servers.
Langflow MCP servers support both streamable HTTP and SSE transport.
* MCP servers: The following endpoints are for managing Hanzo Flow MCP servers and MCP server connections.
They aren't typically called directly; instead, they are used to drive internal functionality in the Hanzo Flow frontend and when running flows that call MCP servers.
Hanzo Flow MCP servers support both streamable HTTP and SSE transport.
* HEAD `/v1/mcp/streamable`: Health check for streamable HTTP MCP.
* GET `/v1/mcp/streamable`: Open streamable HTTP connection for MCP server.
* POST `/v1/mcp/streamable`: Post messages to the MCP server via streamable HTTP.
@@ -400,8 +400,8 @@ Langflow MCP servers support both streamable HTTP and SSE transport.
* POST `/v1/mcp/project/{project_id}/install`: Install MCP client config for Cursor/Windsurf/Claude (local only).
* GET `/v1/mcp/project/{project_id}/installed`: Check which clients have MCP config installed.
* Custom components: You might use these endpoints when developing custom Langflow components for your own use or to share with the Langflow community:
* GET `/v1/all`: Return all available Langflow component types. See [Get all components](/api-reference-api-examples#get-all-components).
* Custom components: You might use these endpoints when developing custom Hanzo Flow components for your own use or to share with the Hanzo Flow community:
* GET `/v1/all`: Return all available Hanzo Flow component types. See [Get all components](/api-reference-api-examples#get-all-components).
* POST `/v1/custom_component`: Build a custom component from code and return its node.
* POST `/v1/custom_component/update`: Update an existing custom component's build config and outputs.
* POST `/v1/validate/code`: Validate a Python code snippet for a custom component.
@@ -434,7 +434,7 @@ The following endpoints are deprecated:
## Next steps
* Use the Langflow API to [run a flow](/api-flows-run).
* Use the Langflow API to [upload files](/api-files).
* Use the Langflow API to [get flow logs](/api-logs).
* Explore all endpoints in the [Langflow API specification](/api).
* Use the Hanzo Flow API to [run a flow](/api-flows-run).
* Use the Hanzo Flow API to [upload files](/api-files).
* Use the Hanzo Flow API to [get flow logs](/api-logs).
* Explore all endpoints in the [Hanzo Flow API specification](/api).
+7 -7
View File
@@ -32,13 +32,13 @@ import exampleJavascriptApiUsersDeleteUser from '!!raw-loader!@site/docs/API-Ref
Use the `/users` endpoint to manage user accounts in Langflow.
Use the `/users` endpoint to manage user accounts in Hanzo Flow.
## Add user
Create a new user account with a given username and password.
Requires authentication as a superuser if the Langflow server has authentication enabled.
Requires authentication as a superuser if the Hanzo Flow server has authentication enabled.
<Tabs>
<TabItem value="Python" label="Python" default>
@@ -59,8 +59,8 @@ Requires authentication as a superuser if the Langflow server has authentication
</Tabs>
The request returns an object describing the new user.
The user's UUID is stored in `user_id` in the Langflow database, and returned as `id` in the `/users` API response.
This `user_id` key is specifically for Langflow user management.
The user's UUID is stored in `user_id` in the Hanzo Flow database, and returned as `id` in the `/users` API response.
This `user_id` key is specifically for Hanzo Flow user management.
<details>
<summary>Result</summary>
@@ -102,7 +102,7 @@ Retrieve information about the authenticated user.
Get a paginated list of all users in the system.
Requires authentication as a superuser if the Langflow server has authentication enabled.
Requires authentication as a superuser if the Hanzo Flow server has authentication enabled.
<Tabs>
<TabItem value="Python" label="Python" default>
@@ -133,7 +133,7 @@ Requires authentication as a superuser if the Langflow server has authentication
Modify an existing user's information with a PATCH request.
Requires authentication as a superuser if the Langflow server has authentication enabled.
Requires authentication as a superuser if the Hanzo Flow server has authentication enabled.
This example activates the specified user's account and makes them a superuser:
@@ -197,7 +197,7 @@ Requires authentication as the target user.
Remove a user account from the system.
Requires authentication as a superuser if the Langflow server has authentication enabled.
Requires authentication as a superuser if the Hanzo Flow server has authentication enabled.
<Tabs>
<TabItem value="Python" label="Python" default>
@@ -1 +1 @@
{"id":"07e5b864-e367-4f52-b647-a48035ae7e5e","username":"langflow","profile_image":null,"store_api_key":null,"is_active":true,"is_superuser":true,"create_at":"2025-05-08T17:59:07.855965","updated_at":"2025-05-28T19:00:42.556460","last_login_at":"2025-05-28T19:00:42.554338","optins":{"github_starred":false,"dialog_dismissed":true,"discord_clicked":false,"mcp_dialog_dismissed":true}}
{"id":"07e5b864-e367-4f52-b647-a48035ae7e5e","username":"flow","profile_image":null,"store_api_key":null,"is_active":true,"is_superuser":true,"create_at":"2025-05-08T17:59:07.855965","updated_at":"2025-05-28T19:00:42.556460","last_login_at":"2025-05-28T19:00:42.554338","optins":{"github_starred":false,"dialog_dismissed":true,"discord_clicked":false,"mcp_dialog_dismissed":true}}

Some files were not shown because too many files have changed in this diff Show More