CodeVetter · Repo Unpack · Contributor handoff
langgenius/dify
This repo is agent-aware: layered AGENTS.md files (root, api/, web/, cli/, e2e/, dify-agent/) define per-area rules that must be read before editing. Backend work runs through `uv run --project api` and root `make` targets; frontend through pnpm/vp; CLI through pnpm with generated artifacts. Generated files (docker-compose.yaml, tree.generated.ts, contracts/generated, openapi specs) must never be hand-edited. The dominant correctness disciplines are tenant scoping, explicit bounded transactions, SSRF-routed egress, Pydantic v2 contracts at controller boundaries, and idempotent Celery tasks.
- Read the nearest AGENTS.md before editing: root `AGENTS.md` (repo gotchas: `uv run --project api`, integration tests CI-only, docker env layering), `api/AGENTS.md` (layer boundaries + typing rules), `web/AGENTS.md` (contracts/i18n/dify-ui + 'this is NOT the Next.js you know' warning), `cli/AGENTS.md` + `cli/ARD.md` (command structure), `e2e/AGENTS.md` (runtime ownership).
- Backend commands: `make lint` (ruff format+check --fix + `api-contract-lint` + `lint-imports` + `dotenv-linter`), `make type-check` (pyrefly + mypy), `make test` / `make test TARGET_TESTS=./api/tests/<path>`; direct Python via `uv run --project api`.
- Layer rule: transport parsing/serialization stays in controllers, orchestration in `services/`, domain policy in `core/` or its domain owner; `libs/` must stay business-agnostic. Pydantic v2 models for req/resp; domain exceptions are translated at the controller boundary (see `ChatApi.post`'s long except-chain).
- Never hand-edit generated artifacts: `docker/docker-compose.yaml` (edit `docker-compose-template.yaml`/`envs` + regenerate via `docker/generate_docker_compose`), `cli/src/commands/tree.generated.ts` (`pnpm tree:gen`), `packages/contracts/generated/*` (regen via `gen-api-contract`), and generated API specs.
- Tenant safety is the #1 trap: scope every tenant-owned read/write by the complete owner chain, propagate `tenant_id` across layers, and rehydrate trusted entities from DB state after payload/async boundaries (pattern: `workflow_execute_task` reloads everything from `AppExecutionParams` ids).
- Egress/storage/config discipline: read config only via `configs.dify_config`, storage only via `extensions.ext_storage.storage`, and outbound HTTP only via `core.helper.ssrf_proxy` (or `core.file.remote_fetcher` for remote files).
- Celery discipline: tasks that may retry must keep side effects idempotent and log affected resource ids; keep write transactions explicit/bounded and never do external I/O inside an open transaction unless a documented consistency contract requires it.
- Monkey-patching order is load-bearing: `app.py`'s `if __name__ == "__main__"` gevent patch must precede socket/lock imports; gunicorn (`gevent` worker class) and Celery (`celery_entrypoint.py`) do their own patching — adding imports above the patch block freezes the process.
- `/system-features` is a minimal unauthenticated bootstrap allowlist, not a config registry — before touching controller schemas or `SystemFeatureModel`, read `controllers/API_SCHEMA_GUIDE.md`.
- Frontend: use generated `consoleQuery`/`consoleClient` from `@/service/console` for backend calls (no handwritten REST/DTO mirrors); user strings must add keys in `web/i18n/locales/en-US/` and update every locale; prefer `@langgenius/dify-ui/*` primitives per the linked contracts in `web/AGENTS.md`.
- Version is unified at 1.17.1 across `api/pyproject.toml`, `web/package.json`, `cli/package.json`, `dify-agent/pyproject.toml` and the compose image tags (`langgenius/dify-api:1.17.1`, `dify-web:1.17.1`, `dify-agent-backend:1.17.1`) — bump coherently.
- Tests an agent can actually run locally: `make test` (unit only), `pnpm -C web test`/`vp test`, `pnpm -C cli test`, `cd dify-agent && make test`, `go test ./...` in dify-agent-runtime. Docker-backed integration, VDB smoke, and e2e are CI-only/opt-in — do not start long-running services during routine work.
- Error-surface convention: each blueprint namespace maps domain errors to HTTP errors in `controllers/<surface>/error.py` (e.g. `web/error.py`, `console/error.py` with `UnauthorizedAndForceLogout`); reuse these instead of raising raw werkzeug exceptions from services.
- Files an agent must read first for backend changes: `api/app_factory.py` (ext order + license gate), `api/configs/app_config.py` (settings pipeline), `api/services/app_generate_service.py` (primary dispatch), the target module's docstrings ('local contracts' per AGENTS.md), and `controllers/API_SCHEMA_GUIDE.md` when touching response schemas. (inferred)