# 🦌 DeerFlow - 2.0 English | [δΈ­ζ–‡](./README_zh.md) | [ζ—₯本θͺž](./README_ja.md) | [FranΓ§ais](./README_fr.md) | [Русский](./README_ru.md) [![Python](https://img.shields.io/badge/Python-3.12%2B-3776AB?logo=python&logoColor=white)](./backend/pyproject.toml) [![Node.js](https://img.shields.io/badge/Node.js-22%2B-339933?logo=node.js&logoColor=white)](./Makefile) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) bytedance%2Fdeer-flow | Trendshift > On February 28th, 2026, DeerFlow claimed the πŸ† #1 spot on GitHub Trending following the launch of version 2. Thanks a million to our incredible community β€” you made this happen! πŸ’ͺπŸ”₯ DeerFlow (**D**eep **E**xploration and **E**fficient **R**esearch **Flow**) is an open-source **super agent harness** that orchestrates **sub-agents**, **memory**, and **sandboxes** to do almost anything β€” powered by **extensible skills**. https://github.com/user-attachments/assets/a8bcadc4-e040-4cf2-8fda-dd768b999c18 > [!NOTE] > **DeerFlow 2.0 is a ground-up rewrite.** It shares no code with v1. If you're looking for the original Deep Research framework, it's maintained on the [`1.x` branch](https://github.com/bytedance/deer-flow/tree/main-1.x) β€” contributions there are still welcome. Active development has moved to 2.0. ## Official Website Learn more and see **real demos** on our [**official website**](https://deerflow.tech). ## Sister Projects image - [**LLM Space**](https://github.com/deer-flow/llm-space) - Meet our secret weapon behind DeerFlow β€” one desktop tool to prototype agent ideas, inspect each harness step, replay failures, and benchmark performance. ## Coding Plan from ByteDance Volcengine - We strongly recommend using Doubao-Seed-2.0-Code, DeepSeek v3.2 and Kimi 2.5 to run DeerFlow - [Learn more](https://www.byteplus.com/en/activity/codingplan?utm_campaign=deer_flow&utm_content=deer_flow&utm_medium=devrel&utm_source=OWO&utm_term=deer_flow) - [δΈ­ε›½ε€§ι™†εœ°εŒΊηš„εΌ€ε‘θ€…θ―·η‚Ήε‡»θΏ™ι‡Œ](https://www.volcengine.com/activity/codingplan?utm_campaign=deer_flow&utm_content=deer_flow&utm_medium=devrel&utm_source=OWO&utm_term=deer_flow) ## InfoQuest DeerFlow has newly integrated the intelligent search and crawling toolset independently developed by BytePlus--[InfoQuest (supports free online experience)](https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest) InfoQuest_banner --- ## Table of Contents - [🦌 DeerFlow - 2.0](#-deerflow---20) - [Official Website](#official-website) - [Coding Plan from ByteDance Volcengine](#coding-plan-from-bytedance-volcengine) - [InfoQuest](#infoquest) - [Table of Contents](#table-of-contents) - [One-Line Agent Setup](#one-line-agent-setup) - [Quick Start](#quick-start) - [Configuration](#configuration) - [Running the Application](#running-the-application) - [Deployment Sizing](#deployment-sizing) - [Option 1: Docker (Recommended)](#option-1-docker-recommended) - [Option 2: Local Development](#option-2-local-development) - [Advanced](#advanced) - [Sandbox Mode](#sandbox-mode) - [MCP Server](#mcp-server) - [IM Channels](#im-channels) - [LangSmith Tracing](#langsmith-tracing) - [Langfuse Tracing](#langfuse-tracing) - [Monocle Tracing](#monocle-tracing) - [Using Multiple Providers](#using-multiple-providers) - [From Deep Research to Super Agent Harness](#from-deep-research-to-super-agent-harness) - [Core Features](#core-features) - [Skills \& Tools](#skills--tools) - [Claude Code Integration](#claude-code-integration) - [Session Goals](#session-goals) - [Manual Context Compaction](#manual-context-compaction) - [Sub-Agents](#sub-agents) - [Sandbox \& File System](#sandbox--file-system) - [Context Engineering](#context-engineering) - [Long-Term Memory](#long-term-memory) - [Recommended Models](#recommended-models) - [Embedded Python Client](#embedded-python-client) - [Scheduled Tasks](#scheduled-tasks) - [Terminal Workbench (TUI)](#terminal-workbench-tui) - [Documentation](#documentation) - [⚠️ Security Notice](#️-security-notice) - [Improper Deployment May Introduce Security Risks](#improper-deployment-may-introduce-security-risks) - [Security Recommendations](#security-recommendations) - [Contributing](#contributing) - [License](#license) - [Acknowledgments](#acknowledgments) - [Key Contributors](#key-contributors) - [Star History](#star-history) ## One-Line Agent Setup If you use Claude Code, Codex, Cursor, Windsurf, or another coding agent, you can hand it the setup instructions in one sentence: ```text Help me clone DeerFlow if needed, then bootstrap it for local development by following https://raw.githubusercontent.com/bytedance/deer-flow/main/Install.md ``` That prompt is intended for coding agents. It tells the agent to clone the repo if needed, choose Docker when available, and stop with the exact next command plus any missing config the user still needs to provide. ## Quick Start ### Configuration 1. **Clone the DeerFlow repository** ```bash git clone https://github.com/bytedance/deer-flow.git cd deer-flow ``` 2. **Run the setup wizard** From the project root directory (`deer-flow/`), run: ```bash make setup ``` This launches an interactive wizard that guides you through choosing an LLM provider, optional web search, and execution/safety preferences such as sandbox mode, bash access, and file-write tools. It generates a minimal `config.yaml` and writes your keys to `.env`. Takes about 2 minutes. The wizard also lets you configure an optional web search provider, or skip it for now. Run `make doctor` at any time to verify your setup and get actionable fix hints. If you are opening a GitHub issue about a local setup or runtime problem, run `make support-bundle`. The command prints reporter next steps, writes a `*-issue-summary.md` file to paste into the issue, a `*-issue-draft.md` file for AI-assisted issue filing, and an optional evidence zip under `.deer-flow/support-bundles/`. If an AI assistant files the issue, start from the draft and replace every REQUIRED placeholder instead of inventing missing facts. Attach the zip only if a maintainer asks for it, or if the summary alone is not enough. Maintainers and AI triage tools can start with `triage.json`; the bundle includes redacted diagnostics and file manifests only, and does not include `.env`, raw conversation messages, or user file contents. > **Advanced / manual configuration**: If you prefer to edit `config.yaml` directly, run `make config` instead to copy the full template. See `config.example.yaml` for the complete reference including CLI-backed providers (Codex CLI, Claude Code OAuth), OpenRouter, Responses API, subagent runtime caps such as `subagents.max_total_per_run`, and more.
Manual model configuration examples ```yaml models: - name: gpt-4o display_name: GPT-4o use: langchain_openai:ChatOpenAI model: gpt-4o api_key: $OPENAI_API_KEY - name: openrouter-gemini-2.5-flash display_name: Gemini 2.5 Flash (OpenRouter) use: langchain_openai:ChatOpenAI model: google/gemini-2.5-flash-preview api_key: $OPENROUTER_API_KEY base_url: https://openrouter.ai/api/v1 - name: gpt-5-responses display_name: GPT-5 (Responses API) use: langchain_openai:ChatOpenAI model: gpt-5 api_key: $OPENAI_API_KEY use_responses_api: true output_version: responses/v1 - name: qwen3-32b-vllm display_name: Qwen3 32B (vLLM) use: deerflow.models.vllm_provider:VllmChatModel model: Qwen/Qwen3-32B api_key: $VLLM_API_KEY base_url: http://localhost:8000/v1 supports_thinking: true when_thinking_enabled: extra_body: chat_template_kwargs: enable_thinking: true ``` OpenRouter and similar OpenAI-compatible gateways should be configured with `langchain_openai:ChatOpenAI` plus `base_url`. If you prefer a provider-specific environment variable name, point `api_key` at that variable explicitly (for example `api_key: $OPENROUTER_API_KEY`). To route OpenAI models through `/v1/responses`, keep using `langchain_openai:ChatOpenAI` and set `use_responses_api: true` with `output_version: responses/v1`. For vLLM 0.19.0, use `deerflow.models.vllm_provider:VllmChatModel`. For Qwen-style reasoning models, DeerFlow toggles reasoning with `extra_body.chat_template_kwargs.enable_thinking` and preserves vLLM's non-standard `reasoning` field across multi-turn tool-call conversations. Legacy `thinking` configs are normalized automatically for backward compatibility. Reasoning models may also require the server to be started with `--reasoning-parser ...`. If your local vLLM deployment accepts any non-empty API key, you can still set `VLLM_API_KEY` to a placeholder value. CLI-backed provider examples: ```yaml models: - name: gpt-5.4 display_name: GPT-5.4 (Codex CLI) use: deerflow.models.openai_codex_provider:CodexChatModel model: gpt-5.4 supports_thinking: true supports_reasoning_effort: true - name: claude-sonnet-4.6 display_name: Claude Sonnet 4.6 (Claude Code OAuth) use: deerflow.models.claude_provider:ClaudeChatModel model: claude-sonnet-4-6 max_tokens: 4096 supports_thinking: true ``` - Codex CLI reads `~/.codex/auth.json` - Claude Code accepts `CLAUDE_CODE_OAUTH_TOKEN`, `ANTHROPIC_AUTH_TOKEN`, `CLAUDE_CODE_CREDENTIALS_PATH`, or `~/.claude/.credentials.json` - ACP agent entries are separate from model providers β€” if you configure `acp_agents.codex`, point it at a Codex ACP adapter such as `npx -y @zed-industries/codex-acp` - On macOS, export Claude Code auth explicitly if needed: ```bash eval "$(python3 scripts/export_claude_code_oauth.py --print-export)" ``` API keys can also be set manually in `.env` (recommended) or exported in your shell: ```bash OPENAI_API_KEY=your-openai-api-key TAVILY_API_KEY=your-tavily-api-key ```
### Running the Application #### Deployment Sizing Use the table below as a practical starting point when choosing how to run DeerFlow: | Deployment target | Starting point | Recommended | Notes | |---------|-----------|------------|-------| | Local evaluation / `make dev` | 4 vCPU, 8 GB RAM, 20 GB free SSD | 8 vCPU, 16 GB RAM | Good for one developer or one light session with hosted model APIs. `2 vCPU / 4 GB` is usually not enough. | | Docker development / `make docker-start` | 4 vCPU, 8 GB RAM, 25 GB free SSD | 8 vCPU, 16 GB RAM | Image builds, bind mounts, and sandbox containers need more headroom than pure local dev. | | Long-running server / `make up` | 8 vCPU, 16 GB RAM, 40 GB free SSD | 16 vCPU, 32 GB RAM | Preferred for shared use, multi-agent runs, report generation, or heavier sandbox workloads. | - These numbers cover DeerFlow itself. If you also host a local LLM, size that service separately. - Linux plus Docker is the recommended deployment target for a persistent server. macOS and Windows are best treated as development or evaluation environments. - If CPU or memory usage stays pinned, reduce concurrent runs first, then move to the next sizing tier. #### Option 1: Docker (Recommended) **Development** (hot-reload, source mounts): ```bash make docker-init # Pull sandbox image (only once or when image updates) make docker-start # Start services (auto-detects sandbox mode from config.yaml) ``` `make docker-start` starts `provisioner` only when `config.yaml` uses provisioner mode (`sandbox.use: deerflow.community.aio_sandbox:AioSandboxProvider` with `provisioner_url`). Docker builds use the upstream `uv` registry by default. If you need faster mirrors in restricted networks, export `UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple` and `NPM_REGISTRY=https://registry.npmmirror.com` before running `make docker-init` or `make docker-start`. Local AIO sandbox control traffic is always direct: loopback/private addresses, single-label cluster hosts, and Docker/Podman internal hostnames do not inherit `HTTP_PROXY` or `HTTPS_PROXY`. External sandbox FQDNs and public IPs still honor environment proxy settings. Backend processes automatically pick up `config.yaml` changes on the next config access, so model metadata updates do not require a manual restart during development. The checkpoint storage settings `database.checkpoint_channel_mode` and `database.checkpoint_delta_snapshot_frequency` are exceptions: both are frozen when the process first builds an agent (including through `DeerFlowClient`) and require a process restart to change safely. > [!TIP] > On Linux, if Docker-based commands fail with `permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock`, add your user to the `docker` group and re-login before retrying. See [CONTRIBUTING.md](CONTRIBUTING.md#linux-docker-daemon-permission-denied) for the full fix. **Production** (builds images locally, mounts runtime config and data): ```bash make up # Build images and start all production services make down # Stop and remove containers ``` Access: http://localhost:2026 For persistent deployments, configure `database.backend` as `sqlite` or `postgres`. The selected backend is shared by the LangGraph checkpointer, LangGraph Store, and DeerFlow application data. The deprecated `checkpointer` section, when present, overrides the first two for backward compatibility. The unified nginx endpoint is same-origin by default and does not emit browser CORS headers. If you run a split-origin or port-forwarded browser client, set `GATEWAY_CORS_ORIGINS` to comma-separated exact origins such as `http://localhost:3000`; the Gateway then applies the CORS allowlist and matching CSRF origin checks. Browser login uses `HttpOnly` session cookies. The login page offers a "keep me signed in" option that extends the browser session when the request is HTTPS (including trusted `X-Forwarded-Proto: https`) or localhost HTTP. The localhost exception uses the direct request `Host` and ignores forwarded host headers. Public HTTP deployments, including many temporary sandbox URLs, fall back to session cookies by default. DeerFlow never stores the password in browser storage; the UI may remember only the email address. DeerFlow still uses `Forwarded` / `X-Forwarded-*` headers to recover the browser-facing scheme and origin behind a proxy. The bundled nginx sets `X-Forwarded-Proto`, but preserves an upstream HTTPS value and does not overwrite every forwarded header. Configure the outer trusted proxy to replace or strip client-supplied forwarding headers before traffic reaches DeerFlow. > [!IMPORTANT] > The Gateway still owns active run tasks in process, so production defaults to a single Gateway worker (`GATEWAY_WORKERS=1`). Multi-worker deployments require Postgres, the Redis stream bridge (`stream_bridge.type: redis`), `run_ownership.heartbeat_enabled: true`, and `run_events.backend: db`; process-local memory/JSONL event stores cannot enforce singleton delivery receipts across workers. The bridge shares SSE delivery and bounded `Last-Event-ID` replay across workers. When a valid reconnect cursor has been trimmed, or a subscriber that already established an empty-stream wait falls behind before its first delivery, Memory and Redis emit a machine-readable SSE `gap` event instead of silently returning a partial replay; the Web UI reloads durable thread/event state and resumes from the retained tail. Lease reconciliation marks runs from dead workers as errors, persists their delivery receipts, publishes the terminal stream marker, schedules retained-stream cleanup, and updates the affected thread status. SSE and `/wait` consumers also refresh durable status on heartbeats as a fallback if terminal publication fails. Malformed Redis reconnect IDs live-tail new events instead of replaying the retained buffer, and the rolling retained-buffer TTL (`stream_ttl_seconds`) remains a cleanup safety net rather than a run timeout. IM channel state and other process-local services still need their own multi-worker coordination. > > With lease heartbeat enabled, a transient RunStore renewal error is retried only until the last confirmed lease expires; the stale worker then cancels local execution and suppresses checkpoint, completion-hook, delivery-receipt, and thread-status finalization. A remote tool side effect already in flight may still be outside local cancellation. > > Reconciliation uses an atomic takeover claim that re-checks the lease after candidate selection, so a successful owner renewal wins over orphan recovery and only one reconciler can report a run as recovered. When multiple Gateway workers share the Docker/AIO or E2B sandbox backend, also configure `sandbox.ownership.type: redis`; E2B uses the leases during background startup and periodic reconciliation so duplicate/orphan cleanup cannot terminate a live peer's sandbox. See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed Docker development guide. #### Option 2: Local Development If you prefer running services locally: Prerequisite: complete the "Configuration" steps above first (`make setup`). `make dev` requires a valid `config.yaml` in the project root. Set `DEER_FLOW_PROJECT_ROOT` to define that root explicitly, or `DEER_FLOW_CONFIG_PATH` to point at a specific config file. Runtime state defaults to `.deer-flow` under the project root and can be moved with `DEER_FLOW_HOME`; skills default to `skills/` under the project root and can be moved with `DEER_FLOW_SKILLS_PATH`. Run `make doctor` to verify your setup before starting. On Windows, run the local development flow from Git Bash. Native `cmd.exe` and PowerShell shells are not supported for the bash-based service scripts, and WSL is not guaranteed because some scripts rely on Git for Windows utilities such as `cygpath`. 1. **Check prerequisites**: ```bash make check # Verifies Node.js 22+, pnpm, uv, nginx ``` 2. **Install dependencies**: ```bash make install # Install backend + frontend dependencies + pre-commit hooks ``` 3. **(Optional) Pre-pull sandbox image**: ```bash # Recommended if using Docker/Container-based sandbox make setup-sandbox ``` 4. **(Optional) Load sample memory data for local review**: ```bash python scripts/load_memory_sample.py ``` This copies the sample fixture into the default local runtime memory file so reviewers can immediately test `Settings > Memory`. See [backend/docs/MEMORY_SETTINGS_REVIEW.md](backend/docs/MEMORY_SETTINGS_REVIEW.md) for the shortest review flow. 5. **Start services**: ```bash make dev ``` 6. **Access**: http://localhost:2026 #### Startup Modes DeerFlow runs the agent runtime inside the Gateway API. Development mode enables hot-reload; production mode uses a pre-built frontend. | | **Local Foreground** | **Local Daemon** | **Docker Dev** | **Docker Prod** | |---|---|---|---|---| | **Dev** | `./scripts/serve.sh --dev`
`make dev` | `./scripts/serve.sh --dev --daemon`
`make dev-daemon` | `./scripts/docker.sh start`
`make docker-start` | β€” | | **Prod** | `./scripts/serve.sh --prod`
`make start` | `./scripts/serve.sh --prod --daemon`
`make start-daemon` | β€” | `./scripts/deploy.sh`
`make up` | | Action | Local | Docker Dev | Docker Prod | |---|---|---|---| | **Stop** | `./scripts/serve.sh --stop`
`make stop` | `./scripts/docker.sh stop`
`make docker-stop` | `./scripts/deploy.sh down`
`make down` | | **Restart** | `./scripts/serve.sh --restart [flags]` | `./scripts/docker.sh restart` | β€” | Gateway owns `/api/langgraph/*` and translates those public LangGraph-compatible paths to its native `/api/*` routers behind nginx. Gateway runs automatically enforce native delivery for artifacts created or modified under `/mnt/user-data/outputs`: `present_files` must present at least one output produced by the current run, and the terminal `run.delivery` receipt must be durably recorded. Runs that do not produce output artifacts keep ordinary conversational behavior. DeerFlow's built-in custom events are available through both LangGraph streaming interfaces: native clients can continue subscribing to `stream_mode="custom"`, while callback-based integrations can consume the same payloads as `on_custom_event` records from `astream_events(version="v2")`. The callback event name matches the payload's `type` field. #### Docker Production Deployment `deploy.sh` supports building and starting separately: ```bash # One-step (build + start) deploy.sh # Two-step (build once, start later) deploy.sh build # build all images deploy.sh start # start pre-built images # Stop deploy.sh down ``` ### Advanced #### Sandbox Mode DeerFlow supports multiple sandbox execution modes: - **Local Execution** (runs sandbox code directly on the host machine) - **Docker Execution** (runs sandbox code in isolated Docker containers) - **Docker Execution with Kubernetes** (runs sandbox code in Kubernetes pods via provisioner service) For Docker development, service startup follows `config.yaml` sandbox mode. In Local/Docker modes, `provisioner` is not started. See the [Sandbox Configuration Guide](backend/docs/CONFIGURATION.md#sandbox) to configure your preferred mode. #### MCP Server DeerFlow supports configurable MCP servers and skills to extend its capabilities. For HTTP/SSE MCP servers, OAuth token flows are supported (`client_credentials`, `refresh_token`). For stdio MCP servers, per-tool call timeouts can be configured with `tool_call_timeout`. MCP routing hints can also prefer a specific MCP tool for matching requests without forbidding other tools. When `tool_search` defers MCP schemas, matching routing metadata can auto-promote up to `tool_search.auto_promote_top_k` deferred schemas before the model call. See the [MCP Server Guide](backend/docs/MCP_SERVER.md) for detailed instructions. #### IM Channels DeerFlow supports receiving tasks from messaging apps. Channels auto-start when configured β€” no public IP required for any of them. DeerFlow can also expose user-owned IM channel connections in the workspace UI. When `channel_connections` is enabled, logged-in users can bind Telegram, Slack, Discord, Feishu/Lark, DingTalk, WeChat, or WeCom from the sidebar / Settings > Channels. It reuses the existing outbound `channels.*` transports, so no public IP or provider callback URL is required. Incoming IM messages then run under the connected DeerFlow user account. See [IM Channel Connections](backend/docs/IM_CHANNEL_CONNECTIONS.md) for setup and security notes. | Channel | Transport | Difficulty | |---------|-----------|------------| | Telegram | Bot API (long-polling) | Easy | | Slack | Socket Mode | Moderate | | Feishu / Lark | WebSocket | Moderate | | WeChat | Tencent iLink (long-polling) | Moderate | | WeCom | WebSocket | Moderate | | DingTalk | Stream Push (WebSocket) | Moderate | **Configuration in `config.yaml`:** ```yaml channels: # LangGraph-compatible Gateway API base URL (default: http://localhost:8001/api) langgraph_url: http://localhost:8001/api # Gateway API URL (default: http://localhost:8001) gateway_url: http://localhost:8001 # Optional: global session defaults for all mobile channels session: assistant_id: lead_agent # or a custom agent name; custom agents are routed via lead_agent + agent_name config: recursion_limit: 100 context: thinking_enabled: true is_plan_mode: false subagent_enabled: false feishu: enabled: true app_id: $FEISHU_APP_ID app_secret: $FEISHU_APP_SECRET # domain: https://open.feishu.cn # China (default) # domain: https://open.larksuite.com # International wecom: enabled: true bot_id: $WECOM_BOT_ID bot_secret: $WECOM_BOT_SECRET slack: enabled: true bot_token: $SLACK_BOT_TOKEN # xoxb-... app_token: $SLACK_APP_TOKEN # xapp-... (Socket Mode) allowed_users: [] # empty = allow all telegram: enabled: true bot_token: $TELEGRAM_BOT_TOKEN # Optional: render final Markdown replies as Telegram Rich Messages. rich_messages: false allowed_users: [] # empty = allow all wechat: enabled: false bot_token: $WECHAT_BOT_TOKEN ilink_bot_id: $WECHAT_ILINK_BOT_ID qrcode_login_enabled: true # optional: allow first-time QR bootstrap when bot_token is absent allowed_users: [] # empty = allow all polling_timeout: 35 # timing values must be positive finite seconds polling_retry_delay: 5 qrcode_poll_interval: 2 qrcode_poll_timeout: 180 state_dir: ./.deer-flow/wechat/state max_inbound_image_bytes: 20971520 max_outbound_image_bytes: 20971520 max_inbound_file_bytes: 52428800 max_outbound_file_bytes: 52428800 # Optional: per-channel / per-user session settings session: assistant_id: mobile-agent # custom agent names are also supported here context: thinking_enabled: false users: "123456789": assistant_id: vip-agent config: recursion_limit: 150 context: thinking_enabled: true subagent_enabled: true dingtalk: enabled: true client_id: $DINGTALK_CLIENT_ID # Client ID of your DingTalk application client_secret: $DINGTALK_CLIENT_SECRET # Client Secret of your DingTalk application allowed_users: [] # empty = allow all card_template_id: "" # Optional: AI Card template ID for streaming typewriter effect ``` Notes: - `assistant_id: lead_agent` calls the default LangGraph assistant directly. - If `assistant_id` is set to a custom agent name, DeerFlow still routes through `lead_agent` and injects that value as `agent_name`, so the custom agent's SOUL/config takes effect for IM channels. - IM channel workers call Gateway's LangGraph-compatible API internally and automatically attach process-local internal auth plus the CSRF cookie/header pair required for thread and run creation. - Feishu/Lark now queues rapid follow-up messages per mapped DeerFlow `thread_id` instead of immediately surfacing the generic busy reply, and topic replies keep a per-message card with a compact source-message preview across queued/running/final patches. Set the corresponding API keys in your `.env` file: ```bash # Telegram TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrSTUvwxYZ # Slack SLACK_BOT_TOKEN=xoxb-... SLACK_APP_TOKEN=xapp-... # Feishu / Lark FEISHU_APP_ID=cli_xxxx FEISHU_APP_SECRET=your_app_secret # WeChat iLink WECHAT_BOT_TOKEN=your_ilink_bot_token WECHAT_ILINK_BOT_ID=your_ilink_bot_id # WeCom WECOM_BOT_ID=your_bot_id WECOM_BOT_SECRET=your_bot_secret # DingTalk DINGTALK_CLIENT_ID=your_client_id DINGTALK_CLIENT_SECRET=your_client_secret ``` **Telegram Setup** 1. Chat with [@BotFather](https://t.me/BotFather), send `/newbot`, and copy the HTTP API token. 2. Set `TELEGRAM_BOT_TOKEN` in `.env` and enable the channel in `config.yaml`. 3. The bot accepts inbound text, photos, and documents (with or without captions). Hosted Bot API downloads are limited to 20 MB per attachment. **Slack Setup** 1. Create a Slack App at [api.slack.com/apps](https://api.slack.com/apps) β†’ Create New App β†’ From scratch. 2. Under **OAuth & Permissions**, add Bot Token Scopes: `app_mentions:read`, `chat:write`, `im:history`, `im:read`, `im:write`, `files:write`. 3. Enable **Socket Mode** β†’ generate an App-Level Token (`xapp-…`) with `connections:write` scope. 4. Under **Event Subscriptions**, subscribe to bot events: `app_mention`, `message.im`. 5. Set `SLACK_BOT_TOKEN` and `SLACK_APP_TOKEN` in `.env` and enable the channel in `config.yaml`. **Feishu / Lark Setup** 1. Create an app on [Feishu Open Platform](https://open.feishu.cn/) β†’ enable **Bot** capability. 2. Add permissions: `im:message`, `im:message.p2p_msg:readonly`, `im:resource`. 3. Under **Events**, subscribe to `im.message.receive_v1` and select **Long Connection** mode. 4. Copy the App ID and App Secret. Set `FEISHU_APP_ID` and `FEISHU_APP_SECRET` in `.env` and enable the channel in `config.yaml`. **WeChat Setup** 1. Enable the `wechat` channel in `config.yaml`. 2. Either set `WECHAT_BOT_TOKEN` in `.env`, or set `qrcode_login_enabled: true` for first-time QR bootstrap. 3. When `bot_token` is absent and QR bootstrap is enabled, watch backend logs for the QR content returned by iLink and complete the binding flow. 4. After the QR flow succeeds, DeerFlow persists the acquired token under `state_dir` for later restarts. 5. For Docker Compose deployments, keep `state_dir` on a persistent volume so the `get_updates_buf` cursor and saved auth state survive restarts. **WeCom Setup** 1. Create a bot on the WeCom AI Bot platform and obtain the `bot_id` and `bot_secret`. 2. Enable `channels.wecom` in `config.yaml` and fill in `bot_id` / `bot_secret`. 3. Set `WECOM_BOT_ID` and `WECOM_BOT_SECRET` in `.env`. 4. Make sure backend dependencies include `wecom-aibot-python-sdk`. The channel uses a WebSocket long connection and does not require a public callback URL. 5. The current integration supports inbound text, image, and file messages. Final images/files generated by the agent are also sent back to the WeCom conversation. **DingTalk Setup** 1. Create a DingTalk application in the [DingTalk Developer Console](https://open.dingtalk.com/) and enable **Robot** capability. 2. Set the message receiving mode to **Stream Mode** in the robot configuration page. 3. Copy the `Client ID` and `Client Secret`, set `DINGTALK_CLIENT_ID` and `DINGTALK_CLIENT_SECRET` in `.env`, and enable the channel in `config.yaml`. 4. *(Optional)* To enable streaming AI Card replies (typewriter effect), create an **AI Card** template on the [DingTalk Card Platform](https://open.dingtalk.com/document/dingstart/typewriter-effect-streaming-ai-card), then set `card_template_id` in `config.yaml` to the template ID. You also need to apply for the `Card.Streaming.Write` and `Card.Instance.Write` permissions. When DeerFlow runs in Docker Compose, IM channels execute inside the `gateway` container. In that case, do not point `channels.langgraph_url` or `channels.gateway_url` at `localhost`; use container service names such as `http://gateway:8001/api` and `http://gateway:8001`, or set `DEER_FLOW_CHANNELS_LANGGRAPH_URL` and `DEER_FLOW_CHANNELS_GATEWAY_URL`. **Commands** Once a channel is connected, you can interact with DeerFlow directly from the chat: | Command | Description | |---------|-------------| | `/new` | Start a new conversation | | `/status` | Show current thread info | | `/models` | List available models | | `/memory` | View memory | | `/help` | Show help | > Messages without a command prefix are treated as regular chat β€” DeerFlow creates a thread and responds conversationally. #### Request Trace Correlation Gateway request trace correlation is disabled by default so existing HTTP responses and log formats stay unchanged. To enable it, set: ```yaml logging: enhance: enabled: true format: text ``` When enabled, every Gateway HTTP response includes `X-Trace-Id`, logs include `trace_id`, and Langfuse traces created by that request include `metadata.deerflow_trace_id` with the same value. Gateway run history also records one terminal `run.delivery` receipt per run, including zero-output and crash-recovered runs. The receipt is persisted before the durable terminal run status during normal execution. Orphan recovery first atomically claims an expired lease and then idempotently backfills the receipt, so a stale recovery scan cannot overwrite a live run's detailed delivery facts. Receipt persistence remains best-effort during an event-store outage. Runs that fail checkpoint preflight (or are cancelled while waiting for prior finalization) keep the existing completion-data behavior: they receive the zero-delivery receipt but do not overwrite RunStore completion fields with an empty snapshot. #### LangSmith Tracing DeerFlow has built-in [LangSmith](https://smith.langchain.com) integration for observability. When enabled, all LLM calls, agent runs, and tool executions are traced and visible in the LangSmith dashboard. Add the following to your `.env` file: ```bash LANGSMITH_TRACING=true LANGSMITH_ENDPOINT=https://api.smith.langchain.com LANGSMITH_API_KEY=lsv2_pt_xxxxxxxxxxxxxxxx LANGSMITH_PROJECT=xxx ``` #### Langfuse Tracing DeerFlow also supports [Langfuse](https://langfuse.com) observability for LangChain-compatible runs. Add the following to your `.env` file: ```bash LANGFUSE_TRACING=true LANGFUSE_PUBLIC_KEY=pk-lf-xxxxxxxxxxxxxxxx LANGFUSE_SECRET_KEY=sk-lf-xxxxxxxxxxxxxxxx LANGFUSE_BASE_URL=https://cloud.langfuse.com ``` If you are using a self-hosted Langfuse instance, set `LANGFUSE_BASE_URL` to your deployment URL. **Trace correlation fields.** Every agent run is annotated with Langfuse's reserved trace attributes so the Sessions and Users pages light up automatically: - `session_id` = LangGraph `thread_id` β€” groups every trace of the same conversation - `user_id` = effective user from `get_effective_user_id()` (falls back to `default` in no-auth mode) - `trace_name` = assistant id (defaults to `lead-agent`) - `tags` = `[env:, model:]` (omitted when not set) - `metadata.deerflow_trace_id` = DeerFlow request correlation id, matching `X-Trace-Id` when request trace correlation is enabled These are injected into `RunnableConfig.metadata` at the graph invocation root for both the gateway path (`runtime/runs/worker.py::run_agent`) and the embedded path (`client.py::DeerFlowClient.stream`), so any LangChain-compatible callback can read them. Set `DEER_FLOW_ENV` (or `ENVIRONMENT`) to tag traces by deployment environment. #### Monocle Tracing DeerFlow also supports [Monocle](https://github.com/monocle2ai/monocle), an OpenTelemetry-based tracer for agentic applications. It records each run end-to-end: LLM calls, agent steps, and tool and MCP invocations, with their inputs, outputs, timings, and token counts. Add the following to your `.env` file: ```bash MONOCLE_TRACING=true MONOCLE_EXPORTERS=file # file, console, okahu, s3, blob, gcs (default: file) OKAHU_API_KEY=okh_xxxxxxxx # required only for the `okahu` exporter ``` Each run writes one trace file to `.monocle/`; open it in the [Monocle VS Code extension](https://marketplace.visualstudio.com/items?itemName=OkahuAI.monocle-apptrace) to inspect the span timeline and token counts. Connect to [Okahu](https://www.okahu.ai), an agent-observability platform, to analyze traces across runs and run trace-based and agentic evaluations (via the `okahu` exporter). Traces capture span inputs and outputs verbatim β€” prompts, tool arguments, and model responses β€” plus token usage and timings. The `file` exporter keeps them on local disk and never rotates or cleans them up, so prune `.monocle/` periodically; the remote exporters (`okahu`, `s3`, `blob`, `gcs`) send that same data off-box, so enable only destinations you trust. Monocle is initialized once at Gateway startup: a configuration error (unknown exporter, missing `OKAHU_API_KEY`) is logged there and tracing stays off until the Gateway restarts. #### Using Multiple Providers LangSmith and Langfuse attach as LangChain callbacks, so you can enable both and DeerFlow reports each run to both. If an enabled provider is missing required credentials or fails to initialize, DeerFlow fails fast and names it. Monocle uses a global OpenTelemetry provider rather than a callback; Langfuse shares that provider, so all three can run together. Because both span processors sit on the same shared provider, Monocle's exporters also see Langfuse's spans when both are enabled. For Docker deployments, tracing is disabled by default. Set `LANGSMITH_TRACING=true` and `LANGSMITH_API_KEY` in your `.env` to enable it. ## From Deep Research to Super Agent Harness DeerFlow started as a Deep Research framework β€” and the community ran with it. Since launch, developers have pushed it far beyond research: building data pipelines, generating slide decks, spinning up dashboards, automating content workflows. Things we never anticipated. That told us something important: DeerFlow wasn't just a research tool. It was a **harness** β€” a runtime that gives agents the infrastructure to actually get work done. So we rebuilt it from scratch. DeerFlow 2.0 is no longer a framework you wire together. It's a super agent harness β€” batteries included, fully extensible. Built on LangGraph and LangChain, it ships with everything an agent needs out of the box: a filesystem, memory, skills, sandbox-aware execution, and the ability to plan and spawn sub-agents for complex, multi-step tasks. Use it as-is. Or tear it apart and make it yours. ## Core Features ### Skills & Tools Skills are what make DeerFlow do *almost anything*. A standard Agent Skill is a structured capability module β€” a Markdown file that defines a workflow, best practices, and references to supporting resources. DeerFlow ships with built-in skills for research, report generation, slide creation, web pages, image and video generation, and more. But the real power is extensibility: add your own skills, replace the built-in ones, or combine them into compound workflows. Skills are loaded progressively β€” only when the task needs them, not all at once. This keeps the context window lean and makes DeerFlow work well even with token-sensitive models. A skill directory is a package boundary: once DeerFlow finds its `SKILL.md`, nested `SKILL.md` files under that package (for example evaluation fixtures) remain supporting data and are not registered as runtime skills. Namespace directories without their own `SKILL.md` can still group nested skills. Users can explicitly activate an enabled skill for a single turn by starting the request with `/skill-name`, for example `/data-analysis analyze uploads/foo.csv`. DeerFlow loads that skill's `SKILL.md` as hidden current-turn context while leaving the base prompt limited to skill metadata. Slash activation respects disabled skills, custom-agent skill whitelists, and existing channel commands such as `/new` and `/help`. An enabled skill's `allowed-tools` policy applies only after that skill is explicitly slash-activated or captured in the thread's active skill context after a `read_file` load. Merely enabling, advertising, or listing a skill in a custom agent's `skills` allowlist does not reduce the lead agent's normal toolset. During a slash-activated run, that explicit skill's policy is authoritative: reading another `SKILL.md` may provide instructions but cannot widen the slash skill's tools. Without slash activation, policies from skills actually loaded into active context retain their union semantics. Once active, the policy filters both model-visible tool schemas and tool execution. Framework discovery tools (`tool_search` and `describe_skill`) remain available so an allowed deferred tool or installed skill can still be discovered, but discovery and promotion never grant permission to execute a business tool omitted from `allowed-tools`. `task` is not framework-exempt; a restrictive skill must list it explicitly to delegate to a subagent. Per-step policy decisions are internal runtime context and are removed from observable or persisted context copies. Registry failures and an active set with no remaining valid skill fail closed to framework-safe tools; individual stale paths are ignored only when another valid active skill remains. This is best-effort behavioral scoping, not a hard security boundary: loading skill instructions through another tool is not captured, and active-skill entries can be evicted from bounded context. When you install `.skill` archives through the Gateway, DeerFlow accepts standard optional frontmatter metadata such as `version`, `author`, and `compatibility` instead of rejecting otherwise valid external skills. Managed integrations install shared read-only skill packs without mixing them into custom skills. The Lark/Feishu CLI integration is available under `Settings β†’ Integrations β†’ Lark / Feishu CLI`; an administrator installs or upgrades the official `lark-*` pack once under `{DEER_FLOW_HOME}/integrations/skills/lark-cli`, and every user discovers that same pack with an independent enabled state. Each user's app configuration and OAuth data remain isolated under `{DEER_FLOW_HOME}/users/{user_id}/integrations/lark-cli/{config,data}`. These secret directories are restricted to `0700`, regular credential files to `0600`, and symlinks are rejected. After installation, users can click **Connect Lark** to open a browser authorization link; no terminal authorization is required. The same UI can request additional permission domains such as Calendar, Docs, or Drive, or a specific OAuth scope reported by `lark-cli`. A cheap status refresh only inspects the local credential tree, so the UI reports **Credentials configured (not live-verified)** until an explicit browser completion performs live token verification. The action then remains **Reconnect Lark** so users can replace or extend authorization. If an agent hits missing Lark authorization during a conversation, the managed `lark-shared` guidance points the user back to the same settings entry with `?settings=integrations`. Installing the Lark skill pack resolves the latest official `larksuite/cli` release from GitHub and downloads that version's skills at install time, so the Gateway needs outbound internet access for that step (it falls back to a bottom-line pinned version if the release lookup fails). The settings page shows the installed version and, when available, the newest published version so an admin can reinstall to upgrade. Air-gapped deployments can pre-stage the archive and point `DEER_FLOW_LARK_CLI_SKILLS_ARCHIVE` at the local file. Integrity does not depend on a pinned archive byte hash (GitHub does not guarantee stable source-archive bytes); instead the download is restricted to the official GitHub host, every archive member passes structural safety guards, and a content hash of the effective installed skill tree (including DeerFlow's injected shared guidance) is recorded so content changes are auditable across reinstalls. When `sandbox.use` selects the AIO provider, the same install also downloads the official Linux amd64 and arm64 CLI release archives, verifies their published SHA-256 checksums, safely extracts one executable per architecture, and mounts the resulting runtime read-only at `/mnt/integrations/lark-cli/runtime`. An architecture-selecting launcher in that mount makes `lark-cli` available in the sandbox `PATH`. Air-gapped AIO deployments can pre-stage a symlink-free runtime tree containing `bin/lark-cli` plus both `linux-{amd64,arm64}/lark-cli` files and set `DEER_FLOW_LARK_CLI_SANDBOX_RUNTIME_DIR` to that directory. > **Sandbox trust boundary:** the browser never receives the Lark app secret, but > agent conversations run `lark-cli` inside the sandbox, so the per-user > credential directories are mounted into it: `config` (holding the long-lived > `appSecret`) is mounted **read-only** and `data` (refreshable OAuth tokens) > writable. Both remain *readable* by any process the agent runs there, so code > reached via prompt injection in a tool result could read them. Treat the > sandbox as inside the Lark credential trust boundary until the sidecar > credential-broker follow-up removes these mounts from sandbox execution. For remote/Kubernetes deployments (the provisioner backend), the sandbox `lark-cli` runtime can instead be supplied by an optional init container that copies the binaries into a shared `emptyDir` β€” no install-time GitHub download and no hostPath/PVC runtime mount. Publish the image under [`docker/lark-cli-init`](docker/lark-cli-init/README.md) and set `LARK_CLI_INIT_IMAGE` on the provisioner; it stays off (legacy behavior) when unset. The Lark integration status (`GET /api/integrations/lark/status`) reports `sandbox_runtime_mode` and `sandbox_runtime_ready` so the Settings UI shows whether `lark-cli` will actually be present in the sandbox at chat time, rather than a green status hiding a later `command not found`. If a trusted operator manages the configured skills directory through an external mount such as MinIO, NFS, or CSI, an administrator can call `POST /api/skills/reload` after changing files. This invalidates skill prompt caches for the current Gateway process and waits up to the bounded refresh timeout so subsequent runs rescan the latest files; running tasks are unchanged. A loader-level filesystem failure returns a generic server error and preserves the last successfully loaded process cache rather than publishing an empty catalog. Uvicorn workers and Kubernetes Pods must each be targeted separately. Direct mount writes bypass the validation, SkillScan, and history applied by DeerFlow's install/edit APIs, so only operator-controlled systems should have write access. Skill installs and agent-managed skill edits run through **SkillScan**, a native deterministic safety scanner before the LLM-based skill scanner. Phase 1 runs offline with no Semgrep/OpenGrep dependency, blocks high-confidence `CRITICAL` findings such as private keys or shell execution, and passes warning findings to the LLM scanner for contextual review. Python instance-client exfiltration checks follow a minimal same-scope evidence chain: a simple name bound to a known client constructor, optional name-to-name aliases, and an actual outbound method or context-manager use supported by that constructor. Constructor roots must be proven imports; bare canonical-looking names are not inferred as modules. Nested scopes do not inherit client handles and inherit only constructor import aliases that are never rebound in the enclosing scope. Comprehensions, walrus-bearing statements, annotations, complex binding targets, unsupported operations, and ambiguous branch flows produce no finding from this signal; skipped constructs conservatively invalidate every name they may bind so stale client state cannot create a finding. A deterministic work budget or recursion limit reached by this best-effort analysis does not discard findings already collected for the file. Set `skill_scan.enabled: false` in `config.yaml` to disable only the deterministic analyzers; safe archive extraction and the LLM scanner still run. DeerFlow also ships with **skill-reviewer**, a public skill for read-only skill quality review. It uses the built-in `review_skill_package` tool to inspect installed skills, local packages, archives, or pasted `SKILL.md` content without activating the target skill, binding its secrets, executing its scripts, or installing it. The tool returns a compact, tag-neutralized JSON payload to the model context and keeps the full raw review payload in the tool artifact for programmatic consumers. The deterministic review core reuses DeerFlow parsing and SkillScan facts, emits versioned JSON contracts under `contracts/skill_review/`, and can be run from the backend CLI: ```bash cd backend uv run python -m deerflow.skills.review.cli ../skills/public/data-analysis --format text --fail-on error --fail-on-incomplete ``` Tools follow the same philosophy. DeerFlow comes with a core toolset β€” web search, web fetch, rendered web capture, file operations, bash execution β€” and supports custom tools via MCP servers and Python functions. Swap anything. Add anything. Advanced deployments can enable pluggable authorization with `authorization.enabled` in `config.yaml`. A configured `AuthorizationProvider` filters denied tools before they reach the model or deferred-tool catalog, then the same provider is checked again before every business-tool execution through the existing guardrail middleware. Gateway `threads:*` and `runs:*` route permissions are derived from the same provider, while existing owner checks and admin-only management gates remain in force. A generated `tool_search` may bypass the second tool check only when it fronts the current build's already-filtered deferred catalog. The built-in RBAC provider supports per-role `tools` and `routes` allow/deny policies and validates that `default_role` names a configured role; authorization is disabled by default. See `config.example.yaml` and the [authorization RFC](docs/plans/2026-07-10-pluggable-authorization-rfc.md). Advanced deployments can also extend the agent runtime itself by declaring zero-argument `AgentMiddleware` classes under `extensions.middlewares` in `config.yaml` or `extensions_config.json`. DeerFlow loads the same configured class list into the lead-agent and subagent pipelines after their built-in runtime middlewares and loop/token guards, but before the terminal-response/safety/clarification tail, so enterprise forks can add domain guardrails, tool-call governance, or observability hooks without patching the built-in middleware builders. Missing packages, invalid classes, and broken modules fail loudly at agent creation. Treat `config.yaml` and `extensions_config.json` as trusted operator-controlled files: middleware paths are code execution, just like custom tool, model, sandbox, guardrail, MCP server, and MCP interceptor declarations. Gateway skill/MCP toggle endpoints preserve this field but do not expose an API write path for `extensions.middlewares`. Per-context parameterization and separate lead-only/subagent-only middleware lists are not supported yet. Gateway-generated follow-up suggestions now normalize both plain-string model output and block/list-style rich content before parsing the JSON array response, so provider-specific content wrappers do not silently drop suggestions. The Web UI composer can polish draft input before sending. The rewrite runs as a short Gateway LLM request using the `input_polish` model configuration, keeps slash skill prefixes such as `/data-analysis`, and only replaces the local draft after the user clicks the polish button; it does not create a thread run or persist a message. Unsent Web UI composer drafts survive page reloads and switching between conversations within the same browser tab. Drafts are isolated by user, agent, and conversation, include a selected slash skill when present, and are cleared once a send is accepted. Attachments and quoted conversation context are intentionally not persisted. The Web UI composer also supports browser-based voice dictation when the browser exposes the Web Speech API. The microphone button transcribes speech into the local draft only; DeerFlow receives only the transcribed text, while audio handling is delegated to the browser or operating system speech-recognition service according to that environment's policy. Users can review or edit the text before sending. The Web UI displays a localized AI-generated-content disclaimer below the composer in both standard and custom-agent conversations, reminding users to verify important information. Interrupted first-turn runs still persist a fallback conversation title, so stopping a streaming response does not leave the thread as "Untitled" after refresh. Streaming Markdown responses animate only newly arrived words; text that is already visible is not faded out and replayed when the next chunk extends the same block. In the Web UI, completed assistant turns can be branched into a new main conversation. The new thread starts from that turn's checkpoint and keeps the preceding replay checkpoint, so the branched response can be regenerated immediately. Regenerating the latest response preserves the thread's current title, including a title you renamed manually after the original response. Legacy or imported histories without checkpoint parent links use a bounded chronological fallback; if no earlier replay checkpoint exists, branching still succeeds with the legacy single-checkpoint shape, while regeneration remains unavailable for that inherited response. Existing single-checkpoint branches are left unchanged rather than attempting an unsafe checkpoint copy. Because workspace files are not checkpointed, the branch only receives a best-effort copy of the current workspace when you branch from the latest turn; branching from an older turn keeps just the restored message history so the branch never inherits files that were created in a later part of the conversation. The Web UI reports completed task time once per run. This is total wall-clock timeβ€”including model reasoning, tool calls, and waitingβ€”not a per-step or model-only thinking duration. Reasoning content remains available through its own separate disclosure. In the Web UI, the latest completed user turn can also be edited and rerun from the message toolbar. DeerFlow restores the conversation checkpoint before that user message, submits the edited text as a new user message, and hides the superseded turn once the replay is in progress or succeeds. This is a conversation-state replay only: files, memory updates, and external tool side effects are not undone. Web UI chat links percent-encode custom thread identifiers before placing them in route segments, so reserved URL characters such as `#` and `?` do not change which conversation is opened. ``` # Paths inside the sandbox container /mnt/skills/public β”œβ”€β”€ research/SKILL.md β”œβ”€β”€ report-generation/SKILL.md β”œβ”€β”€ slide-creation/SKILL.md β”œβ”€β”€ web-page/SKILL.md └── image-generation/SKILL.md /mnt/skills/custom └── your-custom-skill/SKILL.md ← yours /mnt/skills/integrations └── lark-cli/lark-doc/SKILL.md ← managed, read-only ``` #### Claude Code Integration The `claude-to-deerflow` skill lets you interact with a running DeerFlow instance directly from [Claude Code](https://docs.anthropic.com/en/docs/claude-code). Send research tasks, check status, manage threads β€” all without leaving the terminal. **Install the skill**: ```bash npx skills add https://github.com/bytedance/deer-flow --skill claude-to-deerflow ``` Then make sure DeerFlow is running (default at `http://localhost:2026`) and use the `/claude-to-deerflow` command in Claude Code. **What you can do**: - Send messages to DeerFlow and get streaming responses - Choose execution modes: flash (fast), standard, pro (planning), ultra (sub-agents) - Check DeerFlow health, list models/skills/agents - Manage threads and conversation history - Upload files for analysis **Environment variables** (optional, for custom endpoints): ```bash DEERFLOW_URL=http://localhost:2026 # Unified proxy base URL DEERFLOW_GATEWAY_URL=http://localhost:2026 # Gateway API DEERFLOW_LANGGRAPH_URL=http://localhost:2026/api/langgraph # LangGraph API ``` See [`skills/public/claude-to-deerflow/SKILL.md`](skills/public/claude-to-deerflow/SKILL.md) for the full API reference. ### Session Goals Use `/goal ` to attach one active completion condition to the current thread. The goal is thread-scoped state, not a skill activation, so it stays active across turns until DeerFlow determines it has been satisfied or you clear it. Supported commands: ```text /goal finish the implementation and make all tests pass /goal # show the active goal /goal clear # clear it ``` After each Gateway-backed run, DeerFlow evaluates the visible conversation against the active goal with a non-thinking evaluator model. The evaluator must return a typed blocker (`missing_evidence`, `needs_user_input`, `run_failed`, `external_wait`, or `goal_not_met_yet`) plus visible evidence. DeerFlow only injects a hidden continuation when the latest assistant turn is durably checkpointed, the blocker is `goal_not_met_yet`, the thread did not change during evaluation, and the no-progress breaker has not fired. The safety cap defaults to 8 hidden continuations, and repeated identical non-progress evaluations stop after 2 attempts. `/goal clear` and any user-authored new input win over queued continuations. When the goal is satisfied, DeerFlow clears it automatically and publishes the updated thread state. The Web UI shows the active goal above the composer. The same command is available from the TUI and supported IM channels. In the Web UI and supported IM channels, setting `/goal ` also starts a run with the condition as the task; status and clear commands only manage goal state. Setting or clearing a goal is rejected while that thread has a run in flight, including a run owned by another Gateway worker, so the goal checkpoint cannot branch away from an active run's checkpoint lineage. ### Manual Context Compaction Use `/compact` in the Web UI composer to summarize older context for the current thread. DeerFlow keeps the full chat visible, but future model calls use the compacted summary plus recent messages. The command is ignored when there is not enough history to compact, and it is blocked while the thread has a run in flight, including when that run is owned by another Gateway worker. If a multi-worker reservation loses its lease, DeerFlow cancels the checkpoint writer before the replacing run proceeds and returns a retryable conflict after cleanup. Thread-title edits are serialized through the same state-write boundary and show a conflict without closing the rename dialog when a run is active. ### Sub-Agents Complex tasks rarely fit in a single pass. DeerFlow decomposes them. The lead agent can spawn sub-agents on the fly β€” each with its own scoped context, tools, and termination conditions. Sub-agents run in parallel when possible, report back structured results, and the lead agent synthesizes everything into a coherent output. Their configured skills are resolved from the same user-scoped catalog as the lead agent, so user-owned custom skills remain available without exposing another user's version. Their internal AI and tool messages stay scoped to the delegated graph instead of entering the parent chat stream. Reloaded thread history enforces the same boundary: callback-captured sub-agent AI responses remain available in run-event diagnostics but are excluded from the parent transcript, while the parent `task` result remains attached to its subtask card. Long-running sub-agents compact older history when summarization is enabled and re-inject the summary as guarded, hidden durable context before continuing, so recent assistant/tool activity remains grounded in the task. Provider/model request failures are reported as failed sub-agent tasks rather than successful results, so the lead agent and Web UI can react to them correctly. Collapsed sub-agent cards show the effective model and, when the provider returns usage metadata, a cumulative token total that updates after each completed sub-agent LLM call and persists after a reload. When token usage tracking is enabled, completed sub-agent usage is also attributed back to the dispatching step. This is how DeerFlow handles tasks that take minutes to hours: a research task might fan out into a dozen sub-agents, each exploring a different angle, then converge into a single report β€” or a website β€” or a slide deck with generated visuals. One harness, many hands. ### Sandbox & File System `E2BSandboxProvider` uses `wait` as its default overflow policy. It waits for `acquire_timeout`, then fails the agent turn. DeerFlow does not retry the turn automatically. Clients can use the structured error to schedule a retry. Use `burst` with `burst_limit` to permit bounded extra VMs. The `wait` and `reject` policies use only `replicas`. The `reject` policy can remove one warm VM before it returns an error. `replicas` limits one Gateway process. It does not limit all Gateway processes. E2B acquisition uses a bounded executor. Waiting acquisitions do not use the default asyncio executor. An E2B VM keeps its slot until E2B confirms destruction. This rule covers create and reclaim operations. Discovery can find a VM from another Gateway. Shutdown closes an unowned discovery client without destroying its VM. Release stops counting a transition when the VM enters the warm pool. Shutdown races retry remote cleanup after a transient kill failure. Reset destroys tracked active and warm E2B VMs. The old provider instance cannot accept new acquisitions. DeerFlow doesn't just *talk* about doing things. It has its own computer. Each task gets its own execution environment with a full filesystem view β€” skills, workspace, uploads, outputs. The agent reads, writes, and edits files. It can view images and, when configured safely, execute shell commands. The built-in `grep` tool searches either one text file or all matching text files below a directory, so an agent can search an uploaded document directly without first broadening the request to the entire uploads directory. Image bytes loaded for a vision-model call are transient: DeerFlow removes the hidden base64 message after the model consumes it so later checkpoints do not keep duplicating that payload. After each run, DeerFlow records a workspace change summary for the run-owned `workspace` and `outputs` directories. The Web UI shows a compact "files changed" badge on the assistant turn; opening it reveals created, modified, and deleted files with text diffs when safe to display. Uploads are excluded because they are user inputs, not agent-generated changes. Large, binary, or sensitive-looking files are shown as metadata only. With `AioSandboxProvider`, shell execution runs inside isolated containers. With `LocalSandboxProvider`, file tools still map to per-thread directories on the host, but host `bash` is disabled by default because it is not a secure isolation boundary. Re-enable host bash only for fully trusted local workflows. Host bash commands have a wall-clock timeout, and long-lived processes should be started in the background with output redirected to a workspace log. This is the difference between a chatbot with tool access and an agent with an actual execution environment. ``` # Paths inside the sandbox container /mnt/user-data/ β”œβ”€β”€ uploads/ ← your files β”œβ”€β”€ workspace/ ← agents' working directory └── outputs/ ← final deliverables ``` ### Agentic Browser Control Reading a page is not the same as *using* one. Alongside the read-only `web_fetch` and `web_capture` tools, DeerFlow ships an optional agentic browser tool group that keeps a live, per-conversation browser session so the agent can actually operate a page β€” navigate, read the interactive elements, click, type, submit forms, and follow multi-step flows on JavaScript-heavy sites. Each action returns a fresh snapshot of the page's interactive elements, each addressed by a stable `[ref]` number, so the agent acts on what it just observed instead of guessing selectors. Outbound URLs are SSRF-screened by default. It is powered by Playwright and shipped as an optional extra so the core install stays lean: ```bash cd backend uv sync --extra browser uv run playwright install chromium ``` Then uncomment the `group: browser` tool entries in `config.yaml` (`browser_navigate`, `browser_snapshot`, `browser_click`, `browser_type`, `browser_get_text`, `browser_back`, `browser_screenshot`, `browser_close`). `make dev` / Docker startup detects an enabled `browser_navigate` tool and preserves the `browser` extra on dependency syncs. The Gateway fails startup if browser control is configured but Playwright is missing, and `/api/features` hides the Browser UI unless the backend can actually serve it. Keep `headless: true` and `allow_private_addresses: false` for anything but local, trusted debugging. Attaching to an existing Chrome with `cdp_url` cannot enforce DeerFlow's subresource/redirect SSRF guard and therefore fails closed unless `allow_unguarded_cdp: true` explicitly acknowledges that risk; use it only with a trusted local browser. Browser sessions are process-local; keep `GATEWAY_WORKERS=1` while this tool group is enabled because ordinary uvicorn worker dispatch does not provide thread affinity. ### Context Engineering **Isolated Sub-Agent Context**: Each sub-agent runs in its own isolated context. This means that the sub-agent will not be able to see the context of the main agent or other sub-agents. This is important to ensure that the sub-agent is able to focus on the task at hand and not be distracted by the context of the main agent or other sub-agents. **Summarization**: Within a session, DeerFlow manages context aggressively β€” summarizing completed sub-tasks, offloading intermediate results to the filesystem, compressing what's no longer immediately relevant. This lets it stay sharp across long, multi-step tasks without blowing the context window. **Strict Tool-Call Recovery**: When a provider or middleware interrupts a tool-call loop, DeerFlow now strips provider-level raw tool-call metadata on forced-stop assistant messages and injects placeholder tool results for dangling calls before the next model invocation. This keeps OpenAI-compatible reasoning models that strictly validate `tool_call_id` sequences from failing with malformed history errors. **Visible Tool-Run Completion**: For interactive turns, DeerFlow retries an empty post-tool final response once, then surfaces a visible error instead of reporting a silent successful run. ### Long-Term Memory Most agents forget everything the moment a conversation ends. DeerFlow remembers. Across sessions, DeerFlow builds a persistent memory of your profile, preferences, and accumulated knowledge. The more you use it, the better it knows you β€” your writing style, your technical stack, your recurring workflows. Memory is stored locally and stays under your control. Memory updates now skip duplicate fact entries at apply time, so repeated preferences and context do not accumulate endlessly across sessions. File-backed memory now separates global user context from agent facts. Each user has one `memory.json` containing only the project-independent `user` and `history` summaries; every fact is a canonical Markdown file below `agents/{agent_name}/facts/`. Existing lead-agent middleware, API, Settings, import/export, and embedded-client calls that omit `agent_name` resolve inside DeerMem to the reserved `__default__` bucket. That bucket is outside the valid custom-agent name grammar, so a real custom agent named `lead-agent` has a separate fact repository and deleting a custom agent cannot delete a memory-only directory without `config.yaml`. Public agent identifiers are case-insensitive and canonicalized to lowercase. Runtime/API readers still receive a compatibility `facts` array for the selected/default agent, so the frontend does not read agent facts from `memory.json`; structured Markdown `source` metadata is projected to the historical string field at the MemoryManager boundary. An unscoped Clear All first migrates facts from unread legacy per-agent JSON without adopting its soon-to-be-cleared summaries, then removes shared summaries and facts from every agent bucket while preserving agent configuration files, so a later read cannot resurrect skipped legacy facts; an explicitly agent-scoped clear removes only that agent's facts. On first normal read, old facts embedded in the user JSON are migrated automatically to `__default__`; facts written to the earlier implicit `lead-agent` bucket are also moved when that directory is not a real custom agent. Migration and normal writes notify the configured retrieval adapter only after durable storage locks are released. DeerMem uses a scope-aware SQLite FTS5/BM25 adapter by default, stores only rebuildable derived index data under `.retrieval/`, and rebuilds it in the background during Gateway startup or lazily on the first scoped search. A corrupt derived index is recreated automatically. Set `memory.backend_config.retrieval_adapter` to an empty string to disable it and use the local substring fallback. Chinese tokenization is optional; install the backend `memory-zh` extra (`uv sync --extra memory-zh`) for jieba-assisted sub-phrase search. Journaled writes, a shared user lock, and optimistic user-memory revisions prevent silent lost updates. Single-fact repository operations are genuinely incremental: an upsert/delete reads, journals, writes, and re-indexes only the addressed fact files, and returns an explicit incomplete delta rather than a cache-dependent fake full document. Summary change sets merge the supplied `user`/`history` child keys over the persisted sections so a partial update cannot erase omitted siblings; full imports normalize both sections to the complete compatibility schema before applying replacement values. Manager/API compatibility methods materialize a fresh full document only when their public response contract requires one. Fact-level point operations use separate expected user-memory and fact revisions and may explicitly rebase when every addressed fact precondition still holds. Snapshot-derived operations such as scoped clear, capped create, consolidation, and trimming never replay stale delete/trim sets: a manifest conflict reloads the complete document and recomputes the operation, with a bounded retry. Fact paths use the first two hexadecimal characters of `SHA-256(fact_id)` so generated `fact_*` IDs distribute across shards. The cache token combines the shared JSON's nanosecond mtime, size, and persisted revision; this prevents coarse-mtime same-size writes from returning stale data without scanning fact files. Direct out-of-band Markdown edits require an explicit reload. Storage-specific conflicts and corruption are translated at the MemoryManager boundary; the Gateway returns conflict as HTTP 409 and a stable, non-sensitive corruption error as HTTP 500. Full-document `save()` remains a compatibility API and computes a diff before writing; malformed or missing `facts` can no longer silently erase an agent's Markdown files. Legacy migration preserves non-empty `user`/`history` before deleting an agent `memory.json`; conflicting summaries keep the legacy file and fail loudly instead of choosing a winner. Legacy facts in `memory.json` migrate automatically into the reserved `__default__` Markdown bucket on the user's first normal memory read. Operators who prefer to audit or complete the migration before serving traffic can run the optional idempotent CLI from `backend/`: ```bash PYTHONPATH=. python scripts/migrate_memory_markdown.py --all-users --dry-run PYTHONPATH=. python scripts/migrate_memory_markdown.py --all-users # A custom DeerMem root or original non-directory-safe identity can be explicit: PYTHONPATH=. python scripts/migrate_memory_markdown.py --storage-path /path/to/deerflow-home --user-id 'test@example.com' ``` The v1-to-v2 storage migration is one-way for a running application: pre-PR code does not read Markdown facts. Before upgrading a persistent deployment, stop DeerFlow and take a filesystem snapshot or full backup of the configured memory storage root. The migration also durably retains each destructive JSON source beside the original path as `{manifest_filename}.v1.bak` before writing v2 data; an existing mismatched backup or a backup-write failure stops migration without modifying the v1 source. This local backup preserves pre-migration data but is not a substitute for a full snapshot and does not contain facts created after the upgrade. `--user-id` may be repeated. `--all-users` discovers the existing directory-safe buckets below the selected storage root; standalone integrations that passed raw IDs containing characters such as `@` should use the original value with `--user-id`. A failed user's migration is reported without hiding the rest of the audit, and the command exits non-zero when any user fails. The automatic first-read path remains enabled, so running this CLI is not required for startup. ## Recommended Models DeerFlow is model-agnostic β€” it works with any LLM that implements the OpenAI-compatible API. That said, it performs best with models that support: - **Long context windows** (100k+ tokens) for deep research and multi-step tasks - **Reasoning capabilities** for adaptive planning and complex decomposition - **Multimodal inputs** for image understanding and video comprehension - **Strong tool-use** for reliable function calling and structured outputs ## Embedded Python Client DeerFlow can be used as an embedded Python library without running the full HTTP services. The `DeerFlowClient` provides direct in-process access to all agent and Gateway capabilities, returning the same response schemas as the HTTP Gateway API. The HTTP Gateway also exposes `DELETE /api/threads/{thread_id}` to remove DeerFlow-managed local thread data after the LangGraph thread itself has been deleted: ```python from deerflow.client import DeerFlowClient client = DeerFlowClient() # Chat response = client.chat("Analyze this paper for me", thread_id="my-thread") # Streaming (LangGraph SSE protocol: values, messages-tuple, end) for event in client.stream("hello"): if event.type == "messages-tuple" and event.data.get("type") == "ai": print(event.data["content"]) elif event.type == "messages-tuple" and event.data.get("type") == "tool" and "artifact" in event.data: # Structured tool artifacts (for example, ask_clarification cards) # are preserved when the ToolMessage provides one. print(event.data["artifact"]) # Configuration & management β€” returns Gateway-aligned dicts models = client.list_models() # {"models": [...]} skills = client.list_skills() # {"skills": [...]} client.update_skill("web-search", enabled=True) client.upload_files("thread-1", ["./report.pdf"]) # {"success": True, "files": [...]} client.set_goal("thread-1", "finish the implementation and make all tests pass") client.get_goal("thread-1") # {"goal": {...}} or {"goal": None} client.clear_goal("thread-1") ``` The HTTP Gateway accepts `values`, `messages-tuple`, `updates`, `debug`, `tasks`, `checkpoints`, and `custom` stream modes. Unsupported modes such as `messages` and `events`, unsupported non-default run options such as webhooks, delayed execution, or `multitask_strategy="enqueue"`, and undeclared SDK options such as checkpoint durability overrides return `422` before execution instead of being silently ignored or downgraded. All dict-returning methods are validated against Gateway Pydantic response models in CI (`TestGatewayConformance`), ensuring the embedded client stays in sync with the HTTP API schemas. See `backend/packages/harness/deerflow/client.py` for full API documentation. ## Scheduled Tasks DeerFlow now includes a first-class scheduled-task MVP in the workspace. Current MVP capabilities: - Manage tasks at `/workspace/scheduled-tasks` - Choose whether each scheduled task reuses a thread or creates a fresh thread per run - Support `once` and `cron` schedules - Run background scheduled executions as non-interactive DeerFlow runs (`ask_clarification` is not exposed there) - Use `skip` overlap behavior for due cron executions that collide with an active run on the same reused thread - Pause, resume, trigger, inspect history, and delete tasks - Execute scheduled work through the normal DeerFlow run lifecycle Current MVP limits: - No conversation-created `schedule_task` tool yet - No text-only notification jobs - No channel or GitHub dispatch targets - No `interval` schedule type in this first cut Enable background polling with `config.yaml -> scheduler.enabled`. Manual trigger uses the same scheduled-task resource and execution path. ## Terminal Workbench (TUI) `deerflow` is a terminal-native workbench for people who live in the shell. It runs **embedded** over `DeerFlowClient` β€” no Gateway, frontend, nginx, or Docker required β€” while honoring the same `config.yaml`, checkpointer, skills, memory, MCP, and sandbox settings as the rest of DeerFlow. ![DeerFlow TUI](docs/tui/tui-preview.svg) ```bash uv pip install 'deerflow-harness[tui]' # optional 'textual' dependency deerflow # launch the terminal UI (TTY required) deerflow --continue # resume the most recent thread deerflow --resume THREAD # resume a thread by id deerflow --print "summarize this repo" # headless one-shot answer to stdout deerflow --json "hello" # headless newline-delimited StreamEvents ``` A keyboard-driven chat surface with a streaming transcript (Markdown-rendered answers), compact tool-activity cards, a `/` slash-command palette, display-only `/clear`, `/goal` goal management, `/model` and `/threads` pickers, input history, and `Esc` / `Ctrl+C` interrupt. `/clear` removes rows from the current terminal display without deleting the thread or its persisted conversation; `/new` and `/clear` ask you to wait during an active run instead of resetting in-flight display state. Sessions opened in the TUI also appear in the Web UI sidebar β€” it writes the shared thread store under the local default user, so terminal and web stay in sync **without running the Gateway**. See [backend/docs/TUI.md](backend/docs/TUI.md) for the full guide. ## Documentation - [Contributing Guide](CONTRIBUTING.md) - Development environment setup and workflow - [Configuration Guide](backend/docs/CONFIGURATION.md) - Setup and configuration instructions - [Architecture Overview](backend/CLAUDE.md) - Technical architecture details - [Backend Architecture](backend/README.md) - Backend architecture and API reference ## ⚠️ Security Notice ### Improper Deployment May Introduce Security Risks DeerFlow has key high-privilege capabilities including **system command execution, resource operations, and business logic invocation**, and is designed by default to be **deployed in a local trusted environment (accessible only via the 127.0.0.1 loopback interface)**. If you deploy the agent in untrusted environments β€” such as LAN networks, public cloud servers, or other multi-endpoint accessible environments β€” without strict security measures, it may introduce security risks, including: - **Unauthorized illegal invocation**: Agent functionality could be discovered by unauthorized third parties or malicious internet scanners, triggering bulk unauthorized requests that execute high-risk operations such as system commands and file read/write, potentially causing serious security consequences. - **Compliance and legal risks**: If the agent is illegally invoked to conduct cyberattacks, data theft, or other illegal activities, it may result in legal liability and compliance risks. ### Security Recommendations **Note: We strongly recommend deploying DeerFlow in a local trusted network environment.** If you need cross-device or cross-network deployment, you must implement strict security measures, such as: - **IP allowlist**: Use `iptables`, or deploy hardware firewalls / switches with Access Control Lists (ACL), to **configure IP allowlist rules** and deny access from all other IP addresses. - **Authentication gateway**: Configure a reverse proxy (e.g., nginx) and **enable strong pre-authentication**, blocking any unauthenticated access. - **Network isolation**: Where possible, place the agent and trusted devices in the **same dedicated VLAN**, isolated from other network devices. - **Stay updated**: Continue to follow DeerFlow's security feature updates. ## Contributing We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, workflow, and guidelines. Regression coverage includes Docker sandbox mode detection and provisioner kubeconfig-path handling tests in `backend/tests/`. Backend blocking-IO diagnostics are available from the repository root with `make detect-blocking-io`: it statically scans backend business code for blocking IO that may run on the backend event loop, prints a concise summary, and writes complete JSON findings to `.deer-flow/blocking-io-findings.json`. The JSON includes compact review records with `priority`, `location`, `blocking_call`, `event_loop_exposure`, `reason`, and `code`. Gateway artifact serving now forces active web content types (`text/html`, `application/xhtml+xml`, `image/svg+xml`) to download as attachments instead of inline rendering, reducing XSS risk for generated artifacts. ## License This project is open source and available under the [MIT License](./LICENSE). ## Acknowledgments DeerFlow is built upon the incredible work of the open-source community. We are deeply grateful to all the projects and contributors whose efforts have made DeerFlow possible. Truly, we stand on the shoulders of giants. We would like to extend our sincere appreciation to the following projects for their invaluable contributions: - **[LangChain](https://github.com/langchain-ai/langchain)**: Their exceptional framework powers our LLM interactions and chains, enabling seamless integration and functionality. - **[LangGraph](https://github.com/langchain-ai/langgraph)**: Their innovative approach to multi-agent orchestration has been instrumental in enabling DeerFlow's sophisticated workflows. These projects exemplify the transformative power of open-source collaboration, and we are proud to build upon their foundations. ### Key Contributors A heartfelt thank you goes out to the core authors of `DeerFlow`, whose vision, passion, and dedication have brought this project to life: - **[Daniel Walnut](https://github.com/hetaoBackend/)** - **[Henry Li](https://github.com/magiccube/)** Your unwavering commitment and expertise have been the driving force behind DeerFlow's success. We are honored to have you at the helm of this journey. ## Star History [![Star History Chart](https://api.star-history.com/svg?repos=bytedance/deer-flow&type=Date)](https://star-history.com/#bytedance/deer-flow&Date)