mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-23 23:13:58 +08:00
Splits monolithic agent instructions into a slim AGENTS.md hub plus docs/agents/ topic files (philosophy, architecture, components, contracts, testing, anti-patterns) so AI coding agents have a single source of truth for how the project thinks. Removes the .cursor/rules/ directory; AGENTS.md is now the only agent-facing doc. Fixes the long-standing pointer to the empty src/backend/base/langflow/components/ stubs (real components live in src/lfx/src/lfx/components/) and corrects the v2 API description from 'future' to its actual mounted state.
5.6 KiB
5.6 KiB
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.
Package dependency graph (one-way only)
frontend (TS) ──HTTP──▶ langflow (api routers, integrations, distribution)
│
▼ may import
langflow-base (services, graph, db, alembic)
│
▼ may import
lfx (executor core, base primitives, components)
│
▼ may import
langchain-core, pydantic, third-party SDKs
Dependency rules
lfxMUST NOT importlangflow.*orlangflow-base.*. If lfx code needs a service (auth, db, flow lookup), define an interface insidelfxand inject the implementation fromlangflow. The repo currently has ~13 upwardfrom langflow.*imports insidesrc/lfx/src/lfx/components/...(auth, db, helpers) — these are known violations. Do not add more; prefer fixing them.langflow-baseMAY importlfx. It MUST NOT import vendor-specific component modules fromlangflow.components.<vendor>.frontendtalks tolangflowonly via HTTP/WebSocket. No shared filesystem state.
"Where does this code go?" decision tree
Walk top-down. Stop at the first match.
- Is it framework-agnostic flow execution, base component classes, or
Componentprimitives? →src/lfx/src/lfx/(base/for shared primitives,components/for built-ins shipped with lfx). - Is it a FastAPI route, auth, db model, alembic migration, or a lifecycle-managed singleton?
→
src/backend/base/langflow/(api/,services/X/,alembic/versions/). - Is it a vendor integration (OpenAI, Pinecone, Notion, …) — a
Componentsubclass that wraps a third-party SDK? →src/lfx/src/lfx/components/<category>/and update its__init__.pyalphabetically. Never rename the class. - Is it UI, state, or icons?
→
src/frontend/src/. If it consumes a new API field, also updatesrc/frontend/src/types/. - Is it CLI behavior for
lfx run/lfx serve? →src/lfx/src/lfx/cli/. - Is it a SQLAlchemy/SQLModel model change?
→
services/database/models/ANDmake alembic-revision message="..."AND apply withmake alembic-upgrade. - 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.
- Is it shared by both
lfxandlangflow-base? →src/lfx/src/lfx/base/, neverlangflow/base/.
Dependency direction — bad/good examples
- Bad:
from langflow.services.deps import session_scopeinsidesrc/lfx/.... Good: Definelfx.interfaces.SessionProvider, accept it as a constructor arg;langflowwires the concretesession_scopeat startup. - Bad:
from langflow.components.openai import ...insidelangflow-basecore (api/,services/,graph/). Good: Components are loaded dynamically via the component registry; core code referencesComponentonly. - Bad: A new
MyHelperServicethat's just functions. Good: Utility functions go inlangflow/helpers/orlfx/utils/. A service inherits fromservices/base.Serviceand is registered viaservices/factory.py.
API change protocol
api/v1/is the live, stable surface (~25 routers). Existing v1 endpoints MUST stay backwards-compatible: only additive fields, never rename or remove.api/v2/is the active redesign surface (files,mcp,registration,workflow) — both are mounted at runtime inapi/router.py. v2 is not "future"; the old cursor rule was wrong.- Add a new endpoint to v2 only if it (a) replaces a v1 endpoint with a breaking shape change, or (b) belongs to one of the four v2 domains. Otherwise extend v1 additively.
- A breaking change to a v1 endpoint is forbidden. Add a v2 sibling and leave v1 in place.
Cross-cutting change protocol
A change that touches a request/response shape MUST update three places in the same PR:
- The pydantic model in
langflow/api/v{1,2}/schemas.py(or the route's local schema). - 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. - 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.
If you cannot do all three in one PR, do not start.
Service vs utility vs component
- Service (
services/<name>/): lifecycle-managed singleton, inheritsservices.base.Service, registered throughservices/factory.py, accessed viaservices/deps.py. Use when the thing has state, startup/shutdown, or shared connections (db, cache, queue). - Utility (
helpers/,utils/, orlfx/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 ofComponent, withdisplay_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/
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.