

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
1# AGENTS.md23This file provides guidance to AI coding agents (Claude Code, Codex, and others) when working with code in this repository. It is the source of truth; the sibling `CLAUDE.md` imports it via `@AGENTS.md`.45## Project Overview67DeerFlow is a LangGraph-based AI super agent system with a full-stack architecture. The backend provides a "super agent" with sandbox execution, persistent memory, subagent delegation, and extensible tool integration - all operating in per-thread isolated environments.89**Architecture**:10- **Gateway API** (port 8001): REST API plus embedded LangGraph-compatible agent runtime11- **Frontend** (port 3000): Next.js web interface12- **Nginx** (port 2026): Unified reverse proxy entry point13- **Provisioner** (port 8002, optional in Docker dev): Started only when sandbox is configured for provisioner/Kubernetes mode1415**Runtime**:16- `make dev`, Docker dev, and production all run the agent runtime in Gateway via `RunManager` + `run_agent()` + `StreamBridge` (`packages/harness/deerflow/runtime/`). Nginx exposes that runtime at `/api/langgraph/*` and rewrites it to Gateway's native `/api/*` routers.17- Gateway streams `write_file` and `str_replace` argument deltas in bounded batches when clients also subscribe to `values`; messages-only consumers retain the original per-chunk contract, while `values` preserves the complete tool call.18- With `stream_subgraphs`, subgraph frames keep their namespace in the SSE event name (`values|<ns>`, LangGraph Platform style) instead of impersonating root frames — a delegated subagent inherits the parent checkpoint namespace, so publishing its `values` snapshot as bare `values` replaces the whole thread view in SDK clients (#4399). Root-only consumers (file-tool chunk batcher, subagent event persistence, LLM error-fallback detection) ignore namespaced frames. The web frontend does not request subgraph streaming; subtask progress rides root-namespace `task_*` custom events.19- Background subagent identity is deliberately split: the provider `tool_call_id` remains the correlation key for `ToolMessage`, `task_*` SSE events, persisted lifecycle events, frontend cards, and the public `ExtensionData.scope_id` contract (stored as `SubagentResult.external_task_id`), while `SubagentExecutor.execute_async()` generates a full server-side `execution_id` for `SubagentResult.task_id`, the process-wide registry, polling, cancellation, timeout handling, and cleanup. Provider IDs are not globally unique across parent runs, so they must never become registry ownership keys; scheduler closures retain their own `SubagentResult` rather than resolving ownership again through the mutable registry. Terminal subagent token usage travels in the current run's `ToolMessage.additional_kwargs` and is attributed from message state, never through a process-global provider-ID cache.20- Scheduled-task executions must reuse that same Gateway run lifecycle. The scheduler may decide *when* work runs, but it must dispatch through the existing run path rather than introducing a parallel execution stack.21- The background scheduler is single-instance by default. `scheduler.multi_instance=true` opts into lease-aware recovery across Gateway instances and requires shared Postgres, `run_ownership.heartbeat_enabled=true`, and `run_events.backend=db`; otherwise startup rejects the configuration. Live scheduled runs are preserved when a peer starts; expired leases are atomically taken over, stale post-launch writes are fenced by the dispatch lease owner, and the Postgres advisory-locked budget makes `max_concurrent_runs` a shared global cap (including pre-launch reservations).22- Long-running MCP work uses a separate durable task runtime rather than keeping remote task IDs or status polling inside the Agent loop. Explicit `task_toolsets` bind raw submit/status/cancel names; only submit remains Agent-visible, and its wrapper persists the remote handle before returning a local ID. `McpTaskService` claims due rows with leases, resolves a protocol-specific `McpTaskDriver`, and writes normalized snapshots back to `mcp_tasks`; expired leases are the restart-recovery mechanism, and a result returned after expiry must be discarded even when the owner token still matches. The database is the source of truth. `ThreadState` may receive only a bounded projection in later integration work, never the sole recoverable copy.23- Scheduled-task dispatch enforces "at most one active run per task when `overlap_policy=skip`" at the DB layer via the partial unique index `uq_scheduled_task_run_active` (`scheduled_task_runs.task_id WHERE status IN ('queued','running')`). `ScheduledTaskService.dispatch_task`'s `has_active_runs` check is a non-atomic fast path (its own session, separated from the `create()` insert by `await` points), so two concurrent dispatches — a manual `POST /scheduled-tasks/{id}/trigger` racing the poller, a double-click, or a client retry — can both pass it; the index is the atomic arbiter, and the losing `create` surfaces as `ActiveScheduledRunConflict` (translated from `IntegrityError` in the repository) and collapses to the same outcome as the fast path (manual → 409 conflict, scheduled → a `"skipped"` tombstone). The scheduled-skip tombstone is created directly as terminal `"skipped"` (not a transient `"queued"`) so it never occupies the active slot the pre-existing run still holds. Sibling of the `runs` table's `uq_runs_thread_active` (PR #4003), which keys on `thread_id` and so does not cover the default `fresh_thread_per_run` context where every dispatch gets a new thread. Index is status-only, not `overlap_policy`-conditional (the policy is fixed to `"skip"` in the MVP).2425**Project Structure**:26```27deer-flow/28├── Makefile # Root commands (check, install, dev, stop)29├── config.yaml # Main application configuration30├── extensions_config.json # MCP servers and skills configuration31├── backend/ # Backend application (this directory)32│ ├── Makefile # Backend-only commands (dev, gateway, lint)33│ ├── langgraph.json # LangGraph Studio graph configuration34│ ├── packages/35│ │ ├── extension-api/ # public, host-independent extension contracts (import: deerflow_extension_api.*)36│ │ └── harness/ # deerflow-harness package (import: deerflow.*)37│ │ ├── pyproject.toml38│ │ └── deerflow/39│ │ ├── agents/ # LangGraph agent system40│ │ │ ├── lead_agent/ # Main agent (factory + system prompt)41│ │ │ ├── middlewares/ # middleware components (see Middleware Chain section)42│ │ │ ├── memory/ # Memory extraction, queue, prompts43│ │ │ └── thread_state.py # ThreadState schema44│ │ ├── sandbox/ # Sandbox execution system45│ │ │ ├── local/ # Local filesystem provider46│ │ │ ├── sandbox.py # Abstract Sandbox interface47│ │ │ ├── tools.py # bash, ls, read/write/str_replace48│ │ │ └── middleware.py # Sandbox lifecycle management49│ │ ├── subagents/ # Subagent delegation system50│ │ │ ├── builtins/ # general-purpose, bash agents51│ │ │ ├── executor.py # Background execution engine52│ │ │ └── registry.py # Agent registry53│ │ ├── tools/builtins/ # Built-in tools (present_files, ask_clarification, view_image, review_skill_package)54│ │ ├── mcp/ # MCP integration (tools, cache, client)55│ │ ├── integrations/ # Managed first-party integration installers (e.g. Lark CLI skill pack)56│ │ ├── extensions/ # Python plugin loader, registry, placement, and isolation57│ │ ├── models/ # Model factory with thinking/vision support58│ │ ├── skills/ # Skills discovery, loading, parsing59│ │ ├── config/ # Configuration system (app, model, sandbox, tool, etc.)60│ │ ├── community/ # Community tools (search/fetch/scrape, image search, AIO sandbox)61│ │ ├── reflection/ # Dynamic module loading (resolve_variable, resolve_class)62│ │ ├── utils/ # Utilities (network, readability)63│ │ └── client.py # Embedded Python client (DeerFlowClient)64│ ├── app/ # Application layer (import: app.*)65│ │ ├── gateway/ # FastAPI Gateway API66│ │ │ ├── app.py # FastAPI application67│ │ │ └── routers/ # FastAPI route modules (models, mcp, memory, skills, uploads, threads, artifacts, agents, suggestions, channels)68│ │ └── channels/ # IM platform integrations69│ ├── tests/ # Test suite70│ └── docs/ # Documentation71├── frontend/ # Next.js frontend application72└── skills/ # Agent skills directory73 ├── public/ # Public skills (committed)74 └── custom/ # Custom skills (gitignored)75```7677## Important Development Guidelines7879### Documentation Update Policy80**CRITICAL: Always update README.md and AGENTS.md after every code change**8182When making code changes, you MUST update the relevant documentation:83- Update `README.md` for user-facing changes (features, setup, usage instructions)84- Update `AGENTS.md` for development changes (architecture, commands, workflows, internal systems). `CLAUDE.md` imports it via `@AGENTS.md`, so editing `AGENTS.md` updates both.85- Keep documentation synchronized with the codebase at all times86- Ensure accuracy and timeliness of all documentation8788## Commands8990**Root directory** (for full application):91```bash92make check # Check system requirements93make install # Install all dependencies (frontend + backend)94make extension-install SOURCE=... # Install and enable a trusted Python extension95make extension-list # List configured Python extensions96make extension-enable NAME=... # Enable an installed extension97make extension-disable NAME=... # Disable an extension without uninstalling it98make extension-remove NAME=... # Remove a managed extension99make detect-thread-boundaries # Inventory backend executor/thread/event-loop boundaries100make dev # Start all services (Gateway + Frontend + Nginx), with config.yaml preflight101make start # Start production services locally102make stop # Stop all services103```104105**Backend directory** (for backend development only):106```bash107make install # Install backend dependencies108make dev # Run Gateway API with runtime-safe reload (port 8001)109make gateway # Run Gateway API only (port 8001)110make test # Run offline backend tests (excludes live external-API tests)111make test-live # Explicitly run live DeerFlowClient tests with real APIs112make test-blocking-io # Run strict Blockbuster runtime gate on tests/blocking_io/113make lint # Lint with ruff114make format # Format code with ruff115make migrate-rev MSG="..." # Autogenerate a new alembic revision (see Schema Migrations section)116```117118The backend `make dev` target pre-creates and excludes `DEER_FLOW_HOME`119(default: `backend/.deer-flow`) and `backend/sandbox` from Uvicorn's reload120watcher. Do not replace it with a bare `uvicorn --reload`: agent tasks write121Python and other runtime files below `DEER_FLOW_HOME`, which would otherwise122restart the Gateway during an active run.123124More specific `AGENTS.md` files in backend code directories contain the subsystem sections split from this file. Follow the nearest file in the directory tree.125126## Architecture127128### Harness / App Split129130The backend is split into two layers with a strict dependency direction:131132- **Harness** (`packages/harness/deerflow/`): Publishable agent framework package (`deerflow-harness`). Import prefix: `deerflow.*`. Contains agent orchestration, tools, sandbox, models, MCP, skills, config — everything needed to build and run agents.133- **App** (`app/`): Unpublished application code. Import prefix: `app.*`. Contains the FastAPI Gateway API and IM channel integrations (Feishu, Slack, Telegram, DingTalk).134135**Dependency rule**: App imports deerflow, but deerflow never imports app. This boundary is enforced by `tests/test_harness_boundary.py` which runs in CI.136137**Import conventions**:138```python139# Harness internal140from deerflow.agents import make_lead_agent141from deerflow.models import create_chat_model142143# App internal144from app.gateway.app import app145from app.channels.service import start_channel_service146147# App → Harness (allowed)148from deerflow.config import get_app_config149150# Harness → App (FORBIDDEN — enforced by test_harness_boundary.py)151# from app.gateway.routers.uploads import ... # ← will fail CI152```153154Package import hygiene: the `deerflow.agents` and `deerflow.subagents` package155roots expose heavyweight graph/executor entrypoints lazily. Internal modules156that only need lightweight types, config, or registries should import the157concrete submodule instead of adding eager package-root imports that pull in the158tool graph or subagent executor during state/schema imports.159160## Development Workflow161162### Test-Driven Development (TDD) — MANDATORY163164**Every new feature or bug fix MUST be accompanied by unit tests. No exceptions.**165166- Write tests in `backend/tests/` following the existing naming convention `test_<feature>.py`167- Run the full offline suite before and after your change: `make test`168- Tests must pass before a feature is considered complete169- For lightweight config/utility modules, prefer pure unit tests with no external dependencies170- If a module causes circular import issues in tests, add a `sys.modules` mock in `tests/conftest.py` (see existing example for `deerflow.subagents.executor`)171172```bash173# Run all offline tests174make test175176# Explicit live integration tests (requires config.yaml and credentials;177# calls real APIs and may create local side effects)178make test-live179180# Run a specific test file181PYTHONPATH=. uv run pytest tests/test_<feature>.py -v182```183184Direct pytest collection or execution of `tests/test_client_live.py` remains185skipped unless `DEER_FLOW_RUN_LIVE_TESTS=1` is set. Do not add that opt-in to186default CI workflows.187188### Running the Full Application189190From the **project root** directory:191```bash192make dev193```194195This starts all services and makes the application available at `http://localhost:2026`.196197**All startup modes:**198199| | **Local Foreground** | **Local Daemon** | **Docker Dev** | **Docker Prod** |200|---|---|---|---|---|201| **Dev** | `./scripts/serve.sh --dev`<br/>`make dev` | `./scripts/serve.sh --dev --daemon`<br/>`make dev-daemon` | `./scripts/docker.sh start`<br/>`make docker-start` | — |202| **Prod** | `./scripts/serve.sh --prod`<br/>`make start` | `./scripts/serve.sh --prod --daemon`<br/>`make start-daemon` | — | `./scripts/deploy.sh`<br/>`make up` |203204| Action | Local | Docker Dev | Docker Prod |205|---|---|---|---|206| **Stop** | `./scripts/serve.sh --stop`<br/>`make stop` | `./scripts/docker.sh stop`<br/>`make docker-stop` | `./scripts/deploy.sh down`<br/>`make down` |207| **Restart** | `./scripts/serve.sh --restart [flags]` | `./scripts/docker.sh restart` | — |208209**Nginx routing**:210- `/api/langgraph/*` → Gateway embedded runtime (8001), rewritten to `/api/*`211- `/api/*` (other) → Gateway API (8001)212- `/` (non-API) → Frontend (3000)213214### Running Backend Services Separately215216From the **backend** directory:217218```bash219# Gateway API220make gateway221```222223Direct access (without nginx):224- Gateway: `http://localhost:8001`225226### Frontend Configuration227228The frontend uses environment variables to connect to backend services:229- `NEXT_PUBLIC_LANGGRAPH_BASE_URL` - Defaults to `/api/langgraph` (through nginx)230- `NEXT_PUBLIC_BACKEND_BASE_URL` - Defaults to empty string (through nginx)231232When using `make dev` from root, the frontend automatically connects through nginx.233234## Key Features235236### File Upload237238Multi-file upload with automatic document conversion:239- Endpoint: `POST /api/threads/{thread_id}/uploads`240- Supports: PDF, PPT, Excel, Word documents (converted via `markitdown`)241- Rejects directory inputs before copying so uploads stay all-or-nothing242- Reuses one conversion worker per request when called from an active event loop243- Files stored in thread-isolated directories under the resolving user's bucket (`users/{user_id}/threads/{thread_id}/user-data/uploads`). For IM channels the owner is threaded explicitly via the `user_id=` kwarg (see IM Channels → Owner-scoped file storage); HTTP/embedded callers resolve it from `get_effective_user_id()`244- Duplicate filenames in a single upload request are auto-renamed with `_N` suffixes so later files do not truncate earlier files245- Gateway HTTP uploads stage bytes as `.upload-*.part` files and atomically replace the destination only after size validation. These staging files are hidden from upload listings, agent upload context, and sandbox listing/search tools, and swept on Gateway startup if a hard crash leaves one behind.246- Gateway HTTP upload/list/delete handlers offload filesystem work through `deerflow.utils.file_io.run_file_io`, a dedicated ContextVar-preserving file IO executor. Non-mounted sandbox uploads acquire sandboxes with `SandboxProvider.acquire_async()` and offload `read_bytes()` plus `sandbox.update_file()` together.247- Mounted upload paths skip both sandbox acquisition and per-file synchronization. For AIO remote/provisioner deployments this requires an explicit, accurate `sandbox.thread_data_mounts: true`; omission preserves backend auto-detection.248- Agent receives uploaded file list via `UploadsMiddleware`249250See [docs/FILE_UPLOAD.md](docs/FILE_UPLOAD.md) for details.251252### Plan Mode253254TodoList middleware for complex multi-step tasks:255- Controlled via runtime config: `config.configurable.is_plan_mode = True`256- Provides `write_todos` tool for task tracking257- One task in_progress at a time, real-time updates258259See [docs/plan_mode_usage.md](docs/plan_mode_usage.md) for details.260261### Context Summarization262263Automatic conversation summarization when approaching token limits:264- Configured in `config.yaml` under `summarization` key265- Trigger types: tokens, messages, or fraction of max input266- Keeps recent messages while summarizing older ones267- Manual compaction uses `POST /api/threads/{id}/compact`, reuses the same268 `DeerFlowSummarizationMiddleware`, writes a new checkpoint with updated269 `messages` and `summary_text`, and bumps only those channel versions.270 The route uses the shared `reserve_checkpoint_write()` boundary (also used by271 manual state updates). Its short-lived `checkpoint_write` thread operation272 shares the durable active-thread uniqueness constraint with run admission,273 preventing either worker-local or cross-worker checkpoint-write races.274275See [docs/summarization.md](docs/summarization.md) for details.276277### Vision Support278279For models with `supports_vision: true`:280- `ViewImageMiddleware` processes images in conversation281- `view_image_tool` added to agent's toolset282- Images are converted to base64 and injected into a hidden message carrying both a reserved ID prefix and a server-owned metadata marker for the model call; Gateway strips that marker from untrusted input, and the middleware requires both identifiers before removing the message. The `before_model` and `model` node checkpoints for that call still contain the payload; after `after_model` cleanup, subsequent checkpoints retain only lightweight `viewed_images` metadata, while client-chosen IDs survive283284## Code Style285286- Uses `ruff` for linting and formatting287- Line length: 240 characters288- Python 3.12+ with type hints289- Double quotes, space indentation290291## Documentation292293See `docs/` directory for detailed documentation:294- [CONFIGURATION.md](docs/CONFIGURATION.md) - Configuration options295- [ARCHITECTURE.md](docs/ARCHITECTURE.md) - Architecture details296- [API.md](docs/API.md) - API reference297- [SETUP.md](docs/SETUP.md) - Setup guide298- [FILE_UPLOAD.md](docs/FILE_UPLOAD.md) - File upload feature299- [PATH_EXAMPLES.md](docs/PATH_EXAMPLES.md) - Path types and usage300- [summarization.md](docs/summarization.md) - Context summarization301- [plan_mode_usage.md](docs/plan_mode_usage.md) - Plan mode with TodoList302
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| bytedance/deer-flowAGENTS.md · 80k | AGENTS.md | setuptestlint-formatstyle+1 | 93/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/subagents/AGENTS.md · 80k | AGENTS.md | archdependenciesmonorepo | 38/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/tools/AGENTS.md · 80k | AGENTS.md | setuptestarchdependencies+1 | 50/100 | today | |
| bytedance/deer-flowbackend/app/channels/AGENTS.md · 80k | AGENTS.md | monorepo | 29/100 | today | |
| bytedance/deer-flowbackend/app/gateway/AGENTS.md · 80k | AGENTS.md | testing-strategyapimonorepo | 22/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/AGENTS.md · 80k | AGENTS.md | archdependenciesmonorepo | 55/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/agents/AGENTS.md · 80k | AGENTS.md | agent-behaviour | 38/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/agents/memory/AGENTS.md · 80k | AGENTS.md | archdependenciesperformancemonorepo | 18/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/agents/middlewares/AGENTS.md · 80k | AGENTS.md | no sections | 29/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/config/AGENTS.md · 80k | AGENTS.md | styletypesdatabaseperformance | 55/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/extensions/AGENTS.md · 80k | AGENTS.md | setuptest | 47/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/mcp/AGENTS.md · 80k | AGENTS.md | archdependenciesmonorepo | 45/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/models/AGENTS.md · 80k | AGENTS.md | setuparchdependenciesmonorepo | 51/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/persistence/migrations/AGENTS.md · 80k | AGENTS.md | archtypesdependenciesdatabase+1 | 52/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/runtime/AGENTS.md · 80k | AGENTS.md | no sections | 32/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/sandbox/AGENTS.md · 80k | AGENTS.md | testarchdependenciesmonorepo+1 | 22/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/skills/AGENTS.md · 80k | AGENTS.md | archdependenciesperformancemonorepo | 42/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/tracing/AGENTS.md · 80k | AGENTS.md | archdependenciesmonorepo | 38/100 | today | |
| bytedance/deer-flowbackend/packages/harness/deerflow/tui/AGENTS.md · 80k | AGENTS.md | testarchdependenciesmonorepo | 46/100 | today | |
| bytedance/deer-flowfrontend/src/AGENTS.md · 80k | AGENTS.md | styleui | 27/100 | today |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| n8n-io/n8npackages/@n8n/agents/AGENTS.md · 201k | AGENTS.md | buildteststylearch+3 | 100/100 | 14 days ago | |
| aaif-goose/gooseAGENTS.md · 53k | AGENTS.md | setupbuildtestlint-format+7 | 100/100 | 8 days ago | |
| duckduckgo/content-scope-scriptsspecial-pages/AGENTS.md · 70 | AGENTS.md | buildteststylearch+3 | 100/100 | 14 days ago | |
| deepseek-ai/deepseek-harnessnative/landlock-run/AGENTS.md · 104k | AGENTS.md | setupteststylearch+3 | 100/100 | today | |
| code-yeongyu/oh-my-openagentpackages/web/AGENTS.md · 68k | AGENTS.md | setupbuildtestlint-format+6 | 100/100 | 13 days ago | |
| TryGhost/Ghoste2e/AGENTS.md · 55k | AGENTS.md | setupteststylearch+2 | 100/100 | today | |
| vllm-project/vllmAGENTS.md · 89k | AGENTS.md | setuptestlint-formatstyle+5 | 100/100 | 14 days ago | |
| mui/material-uiAGENTS.md · 99k | AGENTS.md | setupbuildtestlint-format+9 | 100/100 | 14 days ago |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/bytedance-deer-flow-backend-agents)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.