{
  "markdown": "# 🦌 DeerFlow - 2.0\n\nEnglish | [中文](./README_zh.md) | [日本語](./README_ja.md) | [Français](./README_fr.md) | [Русский](./README_ru.md)\n\n[![Python](https://img.shields.io/badge/Python-3.12%2B-3776AB?logo=python&logoColor=white)](./backend/pyproject.toml)\n[![Node.js](https://img.shields.io/badge/Node.js-22%2B-339933?logo=node.js&logoColor=white)](./Makefile)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n\n<a href=\"https://trendshift.io/repositories/14699\" target=\"_blank\"><img src=\"https://trendshift.io/api/badge/repositories/14699\" alt=\"bytedance%2Fdeer-flow | Trendshift\" style=\"width: 250px; height: 55px;\" width=\"250\" height=\"55\"/></a>\n> 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! 💪🔥\n\nDeerFlow (**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**.\n\nhttps://github.com/user-attachments/assets/a8bcadc4-e040-4cf2-8fda-dd768b999c18\n\n> [!NOTE]\n> **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.\n\n## Official Website\n\nLearn more and see **real demos** on our [**official website**](https://deerflow.tech).\nThe landing-page case studies open as allowlisted, read-only showcases without requiring a sign-in.\n\n## Sister Projects\n\n<img width=\"446\" height=\"280\" alt=\"image\" align=\"middle\" src=\"https://github.com/user-attachments/assets/077edef4-d560-41af-bb0d-d0a5f14fcc20\" />\n\n- [**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.\n\n## Coding Plan from ByteDance Volcengine\n\n- We strongly recommend using Doubao-Seed-2.0-Code, DeepSeek v3.2 and Kimi 2.5 to run DeerFlow\n- [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)\n- [中国大陆地区的开发者请点击这里](https://www.volcengine.com/activity/codingplan?utm_campaign=deer_flow&utm_content=deer_flow&utm_medium=devrel&utm_source=OWO&utm_term=deer_flow)\n\n## InfoQuest\n\nDeerFlow 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)\n\n<a href=\"https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest\" target=\"_blank\">\n  <img\n    src=\"https://sf16-sg.tiktokcdn.com/obj/eden-sg/hubseh7bsbps/20251208-160108.png\"   alt=\"InfoQuest_banner\"\n  />\n</a>\n\n---\n\n## Table of Contents\n\n- [🦌 DeerFlow - 2.0](#-deerflow---20)\n  - [Official Website](#official-website)\n  - [Coding Plan from ByteDance Volcengine](#coding-plan-from-bytedance-volcengine)\n  - [InfoQuest](#infoquest)\n  - [Table of Contents](#table-of-contents)\n  - [One-Line Agent Setup](#one-line-agent-setup)\n  - [Quick Start](#quick-start)\n    - [Configuration](#configuration)\n    - [Running the Application](#running-the-application)\n      - [Deployment Sizing](#deployment-sizing)\n      - [Option 1: Docker (Recommended)](#option-1-docker-recommended)\n      - [Option 2: Local Development](#option-2-local-development)\n    - [Advanced](#advanced)\n      - [Sandbox Mode](#sandbox-mode)\n      - [MCP Server](#mcp-server)\n      - [IM Channels](#im-channels)\n      - [LangSmith Tracing](#langsmith-tracing)\n      - [Langfuse Tracing](#langfuse-tracing)\n      - [Monocle Tracing](#monocle-tracing)\n      - [Using Multiple Providers](#using-multiple-providers)\n      - [Personal Access Tokens](#personal-access-tokens)\n  - [From Deep Research to Super Agent Harness](#from-deep-research-to-super-agent-harness)\n  - [Core Features](#core-features)\n    - [Skills \\& Tools](#skills--tools)\n      - [Claude Code Integration](#claude-code-integration)\n    - [Session Goals](#session-goals)\n    - [Manual Context Compaction](#manual-context-compaction)\n    - [Sub-Agents](#sub-agents)\n    - [Sandbox \\& File System](#sandbox--file-system)\n    - [Context Engineering](#context-engineering)\n    - [Long-Term Memory](#long-term-memory)\n  - [Recommended Models](#recommended-models)\n  - [Embedded Python Client](#embedded-python-client)\n  - [Scheduled Tasks](#scheduled-tasks)\n  - [Terminal Workbench (TUI)](#terminal-workbench-tui)\n  - [Documentation](#documentation)\n  - [⚠️ Security Notice](#️-security-notice)\n    - [Improper Deployment May Introduce Security Risks](#improper-deployment-may-introduce-security-risks)\n    - [Security Recommendations](#security-recommendations)\n  - [Contributing](#contributing)\n  - [License](#license)\n  - [Acknowledgments](#acknowledgments)\n    - [Key Contributors](#key-contributors)\n  - [Star History](#star-history)\n\n## One-Line Agent Setup\n\nIf you use Claude Code, Codex, Cursor, Windsurf, or another coding agent, you can hand it the setup instructions in one sentence:\n\n```text\nHelp me clone DeerFlow if needed, then bootstrap it for local development by following https://raw.githubusercontent.com/bytedance/deer-flow/main/Install.md\n```\n\nThat 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.\n\n## Quick Start\n\n### Configuration\n\n1. **Clone the DeerFlow repository**\n\n   ```bash\n   git clone https://github.com/bytedance/deer-flow.git\n   cd deer-flow\n   ```\n\n2. **Run the setup wizard**\n\n   From the project root directory (`deer-flow/`), run:\n\n   ```bash\n   make setup\n   ```\n\n   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.\n\n   The wizard also lets you configure an optional web search provider, or skip it for now.\n\n   Run `make doctor` at any time to verify your setup and get actionable fix hints.\n   If you are opening a GitHub issue about a local setup or runtime problem, run\n   `make support-bundle`. The command prints reporter next steps, writes a\n   `*-issue-summary.md` file to paste into the issue, a `*-issue-draft.md` file\n   for AI-assisted issue filing, and an optional evidence zip under\n   `.deer-flow/support-bundles/`. If an AI assistant files the issue, start from\n   the draft and replace every REQUIRED placeholder instead of inventing missing\n   facts. Attach the zip only if a maintainer asks for it, or if the summary\n   alone is not enough. Maintainers and AI triage tools can start with\n   `triage.json`; the bundle includes redacted diagnostics and file manifests\n   only, and does not include `.env`, raw conversation messages, or user file\n   contents.\n\n   > **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.\n\n   Optional per-model pricing must use one currency across all priced models.\n   DeerFlow disables Console cost estimates when currencies are mixed rather\n   than presenting an invalid aggregate.\n\n   <details>\n   <summary>Manual model configuration examples</summary>\n\n   ```yaml\n   models:\n     - name: gpt-4o\n       display_name: GPT-4o\n       use: langchain_openai:ChatOpenAI\n       model: gpt-4o\n       api_key: $OPENAI_API_KEY\n\n     - name: openrouter-gemini-2.5-flash\n       display_name: Gemini 2.5 Flash (OpenRouter)\n       use: langchain_openai:ChatOpenAI\n       model: google/gemini-2.5-flash-preview\n       api_key: $OPENROUTER_API_KEY\n       base_url: https://openrouter.ai/api/v1\n\n     - name: gpt-5-responses\n       display_name: GPT-5 (Responses API)\n       use: langchain_openai:ChatOpenAI\n       model: gpt-5\n       api_key: $OPENAI_API_KEY\n       use_responses_api: true\n       output_version: responses/v1\n\n     - name: qwen3-32b-vllm\n       display_name: Qwen3 32B (vLLM)\n       use: deerflow.models.vllm_provider:VllmChatModel\n       model: Qwen/Qwen3-32B\n       api_key: $VLLM_API_KEY\n       base_url: http://localhost:8000/v1\n       supports_thinking: true\n       when_thinking_enabled:\n         extra_body:\n           chat_template_kwargs:\n             enable_thinking: true\n   ```\n\n   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`).\n\n   To route OpenAI models through `/v1/responses`, keep using `langchain_openai:ChatOpenAI` and set `use_responses_api: true` with `output_version: responses/v1`.\n\n   The setup wizard includes a Z.AI GLM-5.3-Flash profile. Because that model requires thinking and only accepts its own restricted effort levels, the compatibility profile keeps thinking enabled for every foreground and background call and temporarily suppresses DeerFlow's generic effort selector. See `config.example.yaml` for the equivalent manual configuration.\n\n   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. If the endpoint reports a cumulative usage snapshot on every streaming chunk, set `cumulative_stream_usage: true` so DeerFlow converts those snapshots into per-chunk deltas; the option is disabled by default and leaves usage unchanged when a stable completion id is unavailable. 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.\n\n   CLI-backed provider examples:\n\n   ```yaml\n   models:\n     - name: gpt-5.4\n       display_name: GPT-5.4 (Codex CLI)\n       use: deerflow.models.openai_codex_provider:CodexChatModel\n       model: gpt-5.4\n       supports_thinking: true\n       supports_reasoning_effort: true\n\n     - name: claude-sonnet-4.6\n       display_name: Claude Sonnet 4.6 (Claude Code OAuth)\n       use: deerflow.models.claude_provider:ClaudeChatModel\n       model: claude-sonnet-4-6\n       max_tokens: 4096\n       supports_thinking: true\n   ```\n\n   - Codex CLI reads `~/.codex/auth.json`\n   - Claude Code accepts `CLAUDE_CODE_OAUTH_TOKEN`, `ANTHROPIC_AUTH_TOKEN`, `CLAUDE_CODE_CREDENTIALS_PATH`, or `~/.claude/.credentials.json`\n   - 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`\n   - MiniMax Code speaks ACP directly. Install and authenticate it, then add it as an ACP agent:\n\n   ```bash\n   npm install --global @minimax-ai/code\n   mcode login\n   ```\n\n   ```yaml\n   acp_agents:\n     mcode:\n       command: mcode\n       args: [\"acp\"]\n       description: MiniMax Code for implementation, refactoring, debugging, and repository tasks\n       auto_approve_permissions: false\n   ```\n\n   `mcode` must be on the Gateway process's `PATH`; installing it only on the Docker host does not make it available inside the Gateway container. DeerFlow invokes it through `invoke_acp_agent` in a per-thread ACP workspace and forwards enabled MCP servers. Keep `auto_approve_permissions: false` for untrusted tasks; enable it only when MCode must edit files or run commands and you trust the task.\n   - On macOS, export Claude Code auth explicitly if needed:\n\n   ```bash\n   eval \"$(python3 scripts/export_claude_code_oauth.py --print-export)\"\n   ```\n\n   API keys can also be set manually in `.env` (recommended) or exported in your shell:\n\n   ```bash\n   OPENAI_API_KEY=your-openai-api-key\n   TAVILY_API_KEY=your-tavily-api-key\n   ```\n\n   </details>\n\n### Running the Application\n\n#### Deployment Sizing\n\nUse the table below as a practical starting point when choosing how to run DeerFlow:\n\n| Deployment target | Starting point | Recommended | Notes |\n|---------|-----------|------------|-------|\n| 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. |\n| 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. |\n| 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. |\n\n- These numbers cover DeerFlow itself. If you also host a local LLM, size that service separately.\n- Linux plus Docker is the recommended deployment target for a persistent server. macOS and Windows are best treated as development or evaluation environments.\n- If CPU or memory usage stays pinned, reduce concurrent runs first, then move to the next sizing tier.\n\n#### Option 1: Docker (Recommended)\n\nRequires Docker Desktop / Docker Engine and **Docker Compose v2.24+**\n(`docker compose version`). Older Compose clients cannot parse the optional\n`env_file` syntax in `docker/docker-compose-dev.yaml`.\n\n**Development** (hot-reload, source mounts):\n\n```bash\nmake docker-init    # Pull sandbox image (only once or when image updates)\nmake docker-start   # Start services (auto-detects sandbox mode from config.yaml)\nmake docker-logs    # View logs\n```\n\n`make docker-start` starts `provisioner` only when `config.yaml` uses provisioner mode (`sandbox.use: deerflow.community.aio_sandbox:AioSandboxProvider` with `provisioner_url`).\n\nDocker 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`.\n\nLocal AIO sandbox control traffic is always direct: loopback/private addresses,\nsingle-label cluster hosts, and Docker/Podman internal hostnames do not inherit\n`HTTP_PROXY` or `HTTPS_PROXY`. External sandbox FQDNs and public IPs still\nhonor environment proxy settings.\n\nBackend processes automatically pick up `config.yaml` changes on the next config access, so model metadata updates do not require a manual restart during development.\nThe checkpoint storage settings `database.checkpoint_channel_mode` and\n`database.checkpoint_delta.snapshot_frequency` (default `10`) are exceptions:\nboth are frozen when the process first builds an agent (including through\n`DeerFlowClient`) and require a process restart to change safely.\n\nThe optional `database.checkpoint_cache` section (delta channel mode only)\ncaches materialized checkpoint histories: `type` is `memory` (default) or\n`redis`, and `max_entries: 0` disables the cache. The `redis` backend is\nGateway/async-only; the sync TUI/embedded path supports `memory` only. The\ncache is performance-only — results are identical with it disabled — so it is\nnever frozen and workers sharing one checkpoint database may safely run\ndifferent cache settings.\n\n> [!TIP]\n> 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.\n\n**Production** (builds images locally, mounts runtime config and data):\n\n```bash\nmake up     # Build images and start all production services\nmake down   # Stop and remove containers\n```\n\nAccess: http://localhost:2026\n\n`make up` waits for the Gateway `/health` endpoint before reporting success.\nIf the Gateway does not become healthy within the startup window, deployment\nexits non-zero and prints the container status plus recent Gateway logs. The\nproduction image starts from its already-built environment and never resolves\nor installs Python dependencies at container startup.\n\nFor persistent deployments, configure `database.backend` as `sqlite` or\n`postgres`. The selected backend is shared by the LangGraph checkpointer,\nLangGraph Store, and DeerFlow application data. The deprecated `checkpointer`\nsection, when present, overrides the first two for backward compatibility.\n\nThe 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.\n\nBrowser 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.\n\nDeerFlow 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.\n\n> [!IMPORTANT]\n> 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, `/wait`, and internal stream consumers use `stream_bridge.heartbeat_interval_seconds` (default `15`) for idle liveness checks; changing it requires a Gateway restart. 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.\n>\n> After a run publishes its terminal stream marker, its process-local `RunRecord` remains available for the existing five-minute grace period before cleanup; durable run history remains available through `RunStore`, while the stream bridge retains its delivery tail on its separate cleanup schedule.\n>\n> Run cancellation may land on any Gateway worker. A non-owning worker now persists the interrupt or rollback request for the live owner, which observes it during lease renewal and performs the normal cancellation flow; load-balancer routing alone no longer produces a 409. The first accepted action wins even if a retry lands on the owner, and accepted cancellation competes atomically with owner completion. Dead owners still follow lease takeover and orphan recovery. Cancellation latency is therefore bounded by the lease heartbeat interval.\n\n> Cancelling a model recovery probe, including while it is queued or waiting to retry, lets the next call check whether the provider has recovered. Cancellation does not count as a provider failure or release another call's active recovery probe.\n>\n> 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.\n>\n> 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.\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for detailed Docker development guide.\n\n#### Option 2: Local Development\n\nIf you prefer running services locally:\n\nPrerequisite: 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.\nOn 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`.\n\nThe documented root `make` commands invoke repository `.sh` files through Bash\nexplicitly. They therefore continue to work from source archives or filesystems\nthat do not preserve POSIX executable bits. When calling a script directly from\nsuch a checkout, use `bash ./scripts/<name>.sh ...`.\n\n1. **Check prerequisites**:\n   ```bash\n   make check  # Verifies Node.js 22+, pnpm, uv, nginx\n   ```\n\n   The local `make check`, `make install`, `make dev`, and `make start` entry points use a direct `pnpm`/`pnpm.cmd` executable when available and otherwise fall back to `corepack pnpm`. The shared runner and diagnostics resolve repository paths absolutely, so these checks work regardless of the caller's current directory. Corepack runs from `frontend/`, so it honors the `packageManager` version pinned in `frontend/package.json`; enabling a global pnpm shim is not required.\n\n2. **Install dependencies**:\n   ```bash\n   make install  # Install backend + frontend dependencies + pre-commit hooks\n   ```\n\n3. **(Optional) Pre-pull sandbox image**:\n   ```bash\n   # Recommended if using Docker/Container-based sandbox\n   make setup-sandbox\n   ```\n\n4. **(Optional) Load sample memory data for local review**:\n   ```bash\n   python scripts/load_memory_sample.py\n   ```\n   This copies the sample fixture into the default local runtime memory file so reviewers can immediately test `Settings > Memory`.\n   See [backend/docs/MEMORY_SETTINGS_REVIEW.md](backend/docs/MEMORY_SETTINGS_REVIEW.md) for the shortest review flow.\n\n5. **Start services**:\n   ```bash\n   make dev\n   ```\n\n6. **Access**: http://localhost:2026\n\nLocal services always use their internal ports (`8001`, `3000`, and `2026`).\nThe root `.env` variable `PORT` configures only the published Docker ingress;\nit does not change the Next.js port used by `make dev`.\n\n#### Startup Modes\n\nDeerFlow runs the agent runtime inside the Gateway API. Development mode enables hot-reload; production mode uses a pre-built frontend.\n\n| | **Local Foreground** | **Local Daemon** | **Docker Dev** | **Docker Prod** |\n|---|---|---|---|---|\n| **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` | — |\n| **Prod** | `./scripts/serve.sh --prod`<br/>`make start` | `./scripts/serve.sh --prod --daemon`<br/>`make start-daemon` | — | `./scripts/deploy.sh`<br/>`make up` |\n\n| Action | Local | Docker Dev | Docker Prod |\n|---|---|---|---|\n| **Stop** | `./scripts/serve.sh --stop`<br/>`make stop` | `./scripts/docker.sh stop`<br/>`make docker-stop` | `./scripts/deploy.sh down`<br/>`make down` |\n| **Restart** | `./scripts/serve.sh --restart [flags]` | `./scripts/docker.sh restart` | — |\n\n`make start` and `make start-daemon` rebuild the frontend with `next build` on\nevery run. To reuse the last build instead, pass `SKIP_FRONTEND_BUILD=1` (or add\n`--skip-frontend-build` when calling `./scripts/serve.sh --prod` directly). This\nis opt-in: it fails fast when `frontend/.next` has no completed build.\n\nGateway owns `/api/langgraph/*` and translates those public LangGraph-compatible paths to its native `/api/*` routers behind nginx.\n\n#### LangGraph Studio (Optional)\n\nThe default `make dev` topology uses DeerFlow's Gateway-embedded runtime and\ndoes not require LangGraph Studio. To inspect and test the registered lead-agent\ngraph with the standalone development server, run the command from `backend/`\nso the CLI discovers `langgraph.json`:\n\n```bash\ncd backend\nuv run langgraph dev --allow-blocking\n```\n\nThe command prints the local API and Studio UI URLs. This in-memory server is\nfor development and testing only. The flag permits DeerFlow's synchronous\nconfiguration and graph-factory setup during local Studio requests; it must not\nbe treated as a production-server setting. Local Studio authentication is\nhandled automatically, so the connection does not require custom headers. Use\nDeerFlow's documented production startup modes or a supported LangSmith\ndeployment for production workloads. Assistant ownership and provenance in this\nstandalone mode are server-owned: Studio can discover registered graphs and the\nassistants it creates, and normal assistant-version selection remains available.\nBefore the locked local runtime loads its persisted development store, DeerFlow\nrepairs legacy assistant rows and version history so historical client metadata\ncannot restore server privileges or be discarded by the runtime's startup\ncleanup. Keep the backend dependencies synchronized with `uv sync`; this\ncompatibility path requires the declared LangGraph runtime versions and logs a\nwarning if the persisted-store contract no longer matches its expectations.\nThe documented command uses LangGraph's file-based custom-app loader, which is\nalso covered directly by DeerFlow's regression tests.\n\nFor workflows that invoke `backend/langgraph.json` through LangGraph Studio or\na direct LangGraph Server, DeerFlow consumes the authenticated identity\npublished by that runtime and uses it for custom-agent configuration/SOUL, user\nskills and skill policy, uploads, thread data, and memory reads/writes. This\nkeeps authenticated runs out of the shared `default` filesystem bucket, and the\nserver-owned identity takes precedence over ordinary client-supplied `user_id`\nvalues. External identities such as email addresses are mapped to stable,\ncollision-resistant directory-safe user IDs before accessing DeerFlow storage.\nThe default DeerFlow service topology remains the Gateway-embedded runtime\ndescribed above.\n\nGateway 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. Virtual artifact paths are resolved within the same authenticated user and thread scope that produced the output before the output-directory boundary is validated. Runs that do not produce output artifacts keep ordinary conversational behavior.\n\nDeerFlow'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.\n\n#### Docker Production Deployment\n\n`deploy.sh` supports building and starting separately:\n\n```bash\n# One-step (build + start)\ndeploy.sh\n\n# Two-step (build once, start later)\ndeploy.sh build              # build all images\ndeploy.sh start              # start pre-built images\n\n# Stop\ndeploy.sh down\n```\n\n### Advanced\n#### Sandbox Mode\n\nDeerFlow supports multiple sandbox execution modes:\n- **Local Execution** (runs sandbox code directly on the host machine)\n- **Docker Execution** (runs sandbox code in isolated Docker containers)\n- **Docker Execution with Kubernetes** (runs sandbox code in Kubernetes pods via provisioner service)\n\nWhen host Bash is enabled for Local Execution, DeerFlow starts OS detection with `uname -s`, then uses `sw_vers` on Darwin. On Linux, it reads host system files such as `/etc/os-release` only when the active sandbox policy permits it. Host filesystem path checks still apply; after a blocked path, the agent is directed to use a permitted command-only probe or virtual path instead of repeating the rejected command.\n\nFor Docker development, service startup follows `config.yaml` sandbox mode. In Local/Docker modes, `provisioner` is not started.\n\nSee the [Sandbox Configuration Guide](backend/docs/CONFIGURATION.md#sandbox) to configure your preferred mode.\n\n#### MCP Server\n\nDeerFlow supports configurable MCP servers and skills to extend its capabilities.\nFor HTTP/SSE MCP servers, OAuth token flows are supported (`client_credentials`, `refresh_token`).\nFor stdio MCP servers, per-tool call timeouts can be configured with `tool_call_timeout`; durable background-task calls honor the same setting for HTTP/SSE servers as well.\nMCP tool names are prefixed with `<server_name>_` by default to prevent collisions across servers. If a server already namespaces its own tools, set `tool_name_prefix: false` on that server in `extensions_config.json` to keep the original names. Disable the prefix only when the resulting names remain unique across all enabled servers.\nSettings > Tools adds, replaces, and deletes one MCP server at a time through targeted mutations that preserve concurrent sibling changes; deletes use a bodyless URL-addressed request. An invalid stdio command on one server no longer blocks toggling another, while enabling that invalid server remains protected by the command allowlist and surfaces the backend validation message in the UI.\nTargeted updates accept both DeerFlow's `type` field and the MCP-spec `transport` field for SSE/HTTP servers.\nRuntime MCP and skill updates replace `extensions_config.json` atomically, so an interrupted write cannot leave the shared configuration truncated or partially written.\nMCP 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.\n\nOpenViking users can register the official Streamable HTTP endpoint at `/mcp`\nwith an owner-bound USER API key. The native `forget` tool is exposed for\ncapability parity; deletion is irreversible, so it should be called only after\nexplicit user confirmation. DeerFlow does not enforce that confirmation. This\nexplicit, model-selected MCP tool path can run alongside the separate automatic\nOpenViking memory backend; it does not replace automatic turn capture or recall. See the\n[OpenViking MCP tools configuration](backend/docs/MCP_SERVER.md#openviking-mcp-tools).\n\nThe Gateway can adapt an MCP server's ordinary `submit` / `status` / `cancel` tools into durable background tasks. The Agent sees only the configured submit tool and a DeerFlow-local task ID; remote IDs are persisted before the submit call returns, while status and cancel stay internal to the runtime. Polling uses cross-worker leases, exponential retry backoff, scoped MCP sessions, bounded result storage, and restart recovery. A status-tool `isError` is retained as a bounded diagnostic and retried; servers report a permanent remote-task outcome through a normal structured result with `status: \"failed\"`. Remote poll hints are finite positive numbers capped at 24 hours, artifact-reference JSON is limited to 64 KiB, and task/server identifiers are validated against their durable SQL column limits before persistence. Input-required and terminal updates wake the current chat through idempotent Agent runs, while `list_background_tasks` and `cancel_background_task` let the Agent manage tasks without asking users for remote handles. Current-thread tasks are available through `GET /api/threads/{thread_id}/mcp-tasks`, its detail endpoint, and `POST /api/threads/{thread_id}/mcp-tasks/{task_id}/cancel`; when the task runtime actually starts, the Web UI exposes the same safe local view from the chat header with live status refresh, cancellation, and on-demand result, artifact, input-request, status-error, and cancellation-retry details. Default-disabled and memory-backend deployments hide that UI and do not poll the task endpoints. A failed remote cancellation remains queued with backoff, and its latest bounded error and attempt count stay visible in the expanded task card. Enable `mcp_tasks` in `config.yaml`, configure `task_toolsets` with exact raw tool names in `extensions_config.json`, and use a SQL database backend (`sqlite` or `postgres`). Task-enabled server connection, authentication, interceptor, timeout, or binding changes require a Gateway restart so Agent tool discovery and background calls cannot use different configuration versions. `input_required` is notification-only for now: DeerFlow can display the request but cannot yet submit the user's answer back to the remote task.\n\nNotification launch and failed Agent-run deliveries use capped exponential backoff with a visible attempt count and stop after five failed attempts. A permanently rejected target such as a deleted chat is dead-lettered immediately instead of retried forever or recreated. Cancellation endpoints return after durably recording the request; the background service owns the potentially slow remote MCP call and its retry schedule.\n\nNotification runs keep their trusted delivery instruction separate from the framed, untrusted remote event payload. The process-started task runtime—not a hot config read—controls whether the task-management tools are exposed, so changing `mcp_tasks` requires a Gateway restart. When a skill's `allowed-tools` policy is active, `list_background_tasks` and `cancel_background_task` must be declared explicitly like other business tools.\nSee the [MCP Server Guide](backend/docs/MCP_SERVER.md) for detailed instructions.\n\nSecurity: pass per-request MCP credentials only through `config.context.secrets`;\ncredentials must never be placed in either run metadata surface\n(`metadata.auth_token` or `config.metadata.auth_token`). See [MCP credential migration and cleanup](backend/docs/MCP_SERVER.md#migrating-legacy-mcp-credentials)\nfor the supported interceptor flow and the required rotation and retained-copy\ncleanup when migrating from legacy metadata credentials.\n\n#### IM Channels\n\nDeerFlow supports receiving tasks from messaging apps. Channels auto-start when configured — no public IP required for any of them.\n\nDeerFlow 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, WeCom, or Buzz 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.\n\n| Channel | Transport | Difficulty |\n|---------|-----------|------------|\n| Telegram | Bot API (long-polling) | Easy |\n| Slack | Socket Mode | Moderate |\n| Feishu / Lark | WebSocket | Moderate |\n| WeChat | Tencent iLink (long-polling) | Moderate |\n| WeCom | WebSocket | Moderate |\n| DingTalk | Stream Push (WebSocket) | Moderate |\n| Buzz | Nostr relay (WebSocket, NIP-42) | Moderate |\n\n**Configuration in `config.yaml`:**\n\n```yaml\nchannels:\n  # LangGraph-compatible Gateway API base URL (default: http://localhost:8001/api)\n  langgraph_url: http://localhost:8001/api\n  # Gateway API URL (default: http://localhost:8001)\n  gateway_url: http://localhost:8001\n\n  # Maximum queued or provider-reserved inbound messages (default: 1000)\n  inbound_queue_maxsize: 1000\n  # Fixed number of long-lived inbound handler workers (default: 5)\n  max_concurrency: 5\n  # Seconds to drain accepted work before cancelling active handlers (default: 3)\n  shutdown_grace_period_seconds: 3\n\n  # Optional: global session defaults for all mobile channels\n  session:\n    assistant_id: lead_agent  # or a custom agent name; custom agents are routed via lead_agent + agent_name\n    config:\n      recursion_limit: 100\n    context:\n      thinking_enabled: true\n      is_plan_mode: false\n      subagent_enabled: false\n\n  feishu:\n    enabled: true\n    app_id: $FEISHU_APP_ID\n    app_secret: $FEISHU_APP_SECRET\n    # domain: https://open.feishu.cn       # China (default)\n    # domain: https://open.larksuite.com   # International\n\n  wecom:\n    enabled: true\n    bot_id: $WECOM_BOT_ID\n    bot_secret: $WECOM_BOT_SECRET\n\n  slack:\n    enabled: true\n    bot_token: $SLACK_BOT_TOKEN     # xoxb-...\n    app_token: $SLACK_APP_TOKEN     # xapp-... (Socket Mode)\n    allowed_users: []               # empty = allow all\n\n  telegram:\n    enabled: true\n    bot_token: $TELEGRAM_BOT_TOKEN\n    # Optional: render final Markdown replies as Telegram Rich Messages.\n    rich_messages: false\n    allowed_users: []               # empty = allow all\n\n  wechat:\n    enabled: false\n    bot_token: $WECHAT_BOT_TOKEN\n    ilink_bot_id: $WECHAT_ILINK_BOT_ID\n    qrcode_login_enabled: true      # optional: allow first-time QR bootstrap when bot_token is absent\n    allowed_users: []               # empty = allow all\n    polling_timeout: 35             # timing values must be positive finite seconds\n    polling_retry_delay: 5\n    qrcode_poll_interval: 2\n    qrcode_poll_timeout: 180\n    state_dir: ./.deer-flow/wechat/state\n    max_inbound_image_bytes: 20971520\n    max_outbound_image_bytes: 20971520\n    max_inbound_file_bytes: 52428800\n    max_outbound_file_bytes: 52428800\n\n    # Optional: per-channel / per-user session settings\n    session:\n      assistant_id: mobile-agent  # custom agent names are also supported here\n      context:\n        thinking_enabled: false\n      users:\n        \"123456789\":\n          assistant_id: vip-agent\n          config:\n            recursion_limit: 150\n          context:\n            thinking_enabled: true\n            subagent_enabled: true\n\n  dingtalk:\n    enabled: true\n    client_id: $DINGTALK_CLIENT_ID             # Client ID of your DingTalk application\n    client_secret: $DINGTALK_CLIENT_SECRET     # Client Secret of your DingTalk application\n    allowed_users: []                          # empty = allow all\n    card_template_id: \"\"                       # Optional: AI Card template ID for streaming typewriter effect\n```\n\nNotes:\n- `assistant_id: lead_agent` calls the default LangGraph assistant directly.\n- 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.\n- 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.\n- Inbound work is bounded to `inbound_queue_maxsize` pending messages plus `max_concurrency` active workers. When capacity is exhausted, socket/polling providers drop new messages before sending DeerFlow's working acknowledgment and emit a rate-limited warning. Buzz leaves its replay cursor unchanged and reconnects for relay replay; GitHub webhooks return `503`, marking the delivery failed for manual/API redelivery. Shutdown closes admission immediately, keeps channel transports available while accepted messages drain for up to `shutdown_grace_period_seconds`, then cancels and awaits active handlers before closing provider resources; the Gateway's outer timeout can cancel an incomplete shutdown without detaching those resources.\n- 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.\n\nSet the corresponding API keys in your `.env` file:\n\n```bash\n# Telegram\nTELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrSTUvwxYZ\n\n# Slack\nSLACK_BOT_TOKEN=xoxb-...\nSLACK_APP_TOKEN=xapp-...\n\n# Feishu / Lark\nFEISHU_APP_ID=cli_xxxx\nFEISHU_APP_SECRET=your_app_secret\n\n# WeChat iLink\nWECHAT_BOT_TOKEN=your_ilink_bot_token\nWECHAT_ILINK_BOT_ID=your_ilink_bot_id\n\n# WeCom\nWECOM_BOT_ID=your_bot_id\nWECOM_BOT_SECRET=your_bot_secret\n\n# DingTalk\nDINGTALK_CLIENT_ID=your_client_id\nDINGTALK_CLIENT_SECRET=your_client_secret\n```\n\n**Telegram Setup**\n\n1. Chat with [@BotFather](https://t.me/BotFather), send `/newbot`, and copy the HTTP API token.\n2. Set `TELEGRAM_BOT_TOKEN` in `.env` and enable the channel in `config.yaml`.\n3. The bot accepts inbound text, photos, and documents (with or without captions). Hosted Bot API downloads are limited to 20 MB per attachment.\n\n**Slack Setup**\n\n1. Create a Slack App at [api.slack.com/apps](https://api.slack.com/apps) → Create New App → From scratch.\n2. Under **OAuth & Permissions**, add Bot Token Scopes: `app_mentions:read`, `chat:write`, `im:history`, `im:read`, `im:write`, `files:write`.\n3. Enable **Socket Mode** → generate an App-Level Token (`xapp-…`) with `connections:write` scope.\n4. Under **Event Subscriptions**, subscribe to bot events: `app_mention`, `message.im`.\n5. Set `SLACK_BOT_TOKEN` and `SLACK_APP_TOKEN` in `.env` and enable the channel in `config.yaml`.\n\n**Feishu / Lark Setup**\n\n1. Create an app on [Feishu Open Platform](https://open.feishu.cn/) → enable **Bot** capability.\n2. Add permissions: `im:message`, `im:message.p2p_msg:readonly`, `im:resource`.\n3. Under **Events**, subscribe to `im.message.receive_v1` and select **Long Connection** mode.\n4. Copy the App ID and App Secret. Set `FEISHU_APP_ID` and `FEISHU_APP_SECRET` in `.env` and enable the channel in `config.yaml`.\n5. The bot supports inbound text, image, and file messages. Inbound attachment downloads are limited to 20 MB per attachment.\n\n**WeChat Setup**\n\n1. Enable the `wechat` channel in `config.yaml`.\n2. Either set `WECHAT_BOT_TOKEN` in `.env`, or set `qrcode_login_enabled: true` for first-time QR bootstrap.\n3. 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.\n4. After the QR flow succeeds, DeerFlow persists the acquired token under `state_dir` for later restarts.\n5. For Docker Compose deployments, keep `state_dir` on a persistent volume so the `get_updates_buf` cursor and saved auth state survive restarts.\n\n**WeCom Setup**\n\n1. Create a bot on the WeCom AI Bot platform and obtain the `bot_id` and `bot_secret`.\n2. Enable `channels.wecom` in `config.yaml` and fill in `bot_id` / `bot_secret`.\n3. Set `WECOM_BOT_ID` and `WECOM_BOT_SECRET` in `.env`.\n4. Make sure backend dependencies include `wecom-aibot-python-sdk`. The channel uses a WebSocket long connection and does not require a public callback URL.\n5. 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.\n\n**DingTalk Setup**\n\n1. Create a DingTalk application in the [DingTalk Developer Console](https://open.dingtalk.com/) and enable **Robot** capability.\n2. Set the message receiving mode to **Stream Mode** in the robot configuration page.\n3. Copy the `Client ID` and `Client Secret`, set `DINGTALK_CLIENT_ID` and `DINGTALK_CLIENT_SECRET` in `.env`, and enable the channel in `config.yaml`.\n4. *(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.\n\n\nWhen 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`.\n\n**Commands**\n\nOnce a channel is connected, you can interact with DeerFlow directly from the chat:\n\n| Command | Description |\n|---------|-------------|\n| `/new` | Start a new conversation |\n| `/status` | Show current thread info |\n| `/models` | List available models |\n| `/memory` | View memory |\n| `/agent list` | List your Custom Agents |\n| `/agent use <name>` | Start a new conversation with a Custom Agent |\n| `/help` | Show help |\n\n> Messages without a command prefix are treated as regular chat — DeerFlow creates a thread and responds conversationally.\n\nAgent selection is conversation-scoped: `/agent use <name>` starts a fresh conversation and pins that Custom Agent in the thread metadata. Existing conversations never switch agents midway, the selection survives a Gateway restart, and opening the IM-created thread in the Web UI continues through the same Custom Agent.\nUse `/agent use lead_agent` to return to the default agent in a new conversation.\n\n#### Request Trace Correlation\n\nEvery Gateway HTTP response carries an `X-Trace-Id` header. The id is inherited\nfrom an inbound `X-Trace-Id` when the caller sends one and generated otherwise, so\na proxy or an upstream service can pin one id across services. It needs no\nconfiguration and cannot be turned off.\n\nThe same id stays attached to work that outlives the HTTP response: the detached\nrun task, any subagents it delegates to, and the background memory-update threads.\nIt is recorded as `deerflow_trace_id` on the run record (visible in the runs API),\nin the thread's checkpoint metadata, and in Langfuse traces. Scheduled tasks, MCP\ntask notification runs, and IM channel messages start outside HTTP and mint their\nown id per occurrence.\n\nLog records carry that id only when enhanced logging is on:\n\n```yaml\nlogging:\n  enhance:\n    enabled: true   # print trace_id into log records\n    format: text    # or json\n```\n\nThis is off by default because turning it on changes the log format. `logging` is\nrestart-required, so edit `config.yaml` and restart the Gateway. The setting\naffects log output only — the id, the response header, and the run metadata are\nunaffected.\n\n`deerflow_trace_id` is a DeerFlow correlation id: it is not a run id, and it is not\na provider's native trace id. It is not a lookup key either — nothing resolves a\nthread or a run from it; use it to correlate log lines. A `deerflow_trace_id` sent\nin a run request's `metadata` or `config.context` is ignored and overwritten, so\nthe response header, the logs, and the persisted run can never disagree. To pin a\ncorrelation id, send the `X-Trace-Id` header.\n\nGateway run history also records one terminal `run.delivery` receipt per run,\nincluding zero-output and crash-recovered runs. The receipt is persisted before\nthe durable terminal run status during normal execution. Orphan recovery first\natomically claims an expired lease and then idempotently backfills the receipt,\nso a stale recovery scan cannot overwrite a live run's detailed delivery facts.\nReceipt persistence remains best-effort during an event-store outage. Runs that\nfail checkpoint preflight (or are cancelled while waiting for prior\nfinalization) keep the existing completion-data behavior: they receive the\nzero-delivery receipt but do not overwrite RunStore completion fields with an\nempty snapshot.\n\nThe same run event history records loop-detection decisions and deferred MCP\ntool promotions for both the lead agent and ordinary task subagents. Promotion\nevents identify newly promoted deferred-tool names and whether routing metadata or\n`tool_search` selected them, without copying the search query, routing keywords,\nschemas, arguments, results, or catalog hash into the promotion event itself.\n\n#### LangSmith Tracing\n\nDeerFlow 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.\n\nAdd the following to your `.env` file:\n\n```bash\nLANGSMITH_TRACING=true\nLANGSMITH_ENDPOINT=https://api.smith.langchain.com\nLANGSMITH_API_KEY=lsv2_pt_xxxxxxxxxxxxxxxx\nLANGSMITH_PROJECT=xxx\n```\n\n#### Langfuse Tracing\n\nDeerFlow also supports [Langfuse](https://langfuse.com) observability for LangChain-compatible runs.\n\nAdd the following to your `.env` file:\n\n```bash\nLANGFUSE_TRACING=true\nLANGFUSE_PUBLIC_KEY=pk-lf-xxxxxxxxxxxxxxxx\nLANGFUSE_SECRET_KEY=sk-lf-xxxxxxxxxxxxxxxx\nLANGFUSE_BASE_URL=https://cloud.langfuse.com\n```\n\nIf you are using a self-hosted Langfuse instance, set `LANGFUSE_BASE_URL` to your deployment URL.\n\n**Trace correlation fields.** Every agent run is annotated with Langfuse's reserved trace attributes so the Sessions and Users pages light up automatically:\n\n- `session_id` = LangGraph `thread_id` — groups every trace of the same conversation\n- `user_id` = effective user from `get_effective_user_id()` (falls back to `default` in no-auth mode)\n- `trace_name` = assistant id (defaults to `lead-agent`)\n- `tags` = `[env:<DEER_FLOW_ENV>, model:<model_name>]` (omitted when not set)\n- `metadata.deerflow_trace_id` = DeerFlow request correlation id, matching `X-Trace-Id` when request trace correlation is enabled\n\nThese 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.\n\n#### Monocle Tracing\n\nDeerFlow 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.\n\nAdd the following to your `.env` file:\n\n```bash\nMONOCLE_TRACING=true\nMONOCLE_EXPORTERS=file          # file, console, okahu, s3, blob, gcs (default: file)\nOKAHU_API_KEY=okh_xxxxxxxx      # required only for the `okahu` exporter\n```\n\nEach 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).\n\nTraces 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.\n\n#### Using Multiple Providers\n\nLangSmith 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.\n\nFor Docker deployments, tracing is disabled by default. Set `LANGSMITH_TRACING=true` and `LANGSMITH_API_KEY` in your `.env` to enable it.\n\n#### Existing-Run Stream Actions\n\nExisting-run SSE joins are observation-only on `GET`: supplying\n`action=interrupt|rollback` returns `405`. Cancellation on this stream route is\n`POST`-only and requires the `runs:cancel` permission. Accordingly, the OpenAPI\ncontract exposes `action` and `wait` only on `POST`; the `GET` operation exposes\nonly its path parameters.\n\n#### Personal Access Tokens\n\nNon-interactive clients (CI pipelines, scripts, server-to-server integrations)\ncan call the Gateway API with a **personal access token (PAT)** instead of a\nbrowser session. Create one while logged in via `POST /api/v1/auth/pats` — the\nraw `dfp_...` value is shown exactly once; only its SHA-256 digest is stored —\nthen send it as a Bearer credential:\n\n```http\nPOST /api/threads/search\nAuthorization: Bearer dfp_...\nContent-Type: application/json\n\n{}\n```\n\nEach token runs with its owning user's identity (owner filtering and per-user\nmemory keep working), carries a scope set that can only narrow that user's\npermissions, and is admitted only to the thread/run lifecycle routes — every\nother route answers `403` to PAT callers, and a PAT never carries admin\ncapability. Tokens can be listed and revoked at any time; revocation is\nimmediate. PATs require a database backend (SQLite/PostgreSQL). Full\nreference: [API Reference — Personal Access Tokens](backend/docs/API.md#personal-access-tokens).\n\n## From Deep Research to Super Agent Harness\n\nDeerFlow 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.\n\nThat 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.\n\nSo we rebuilt it from scratch.\n\nDeerFlow 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.\n\nUse it as-is. Or tear it apart and make it yours.\n\n## Core Features\n\n### Skills & Tools\n\nSkills are what make DeerFlow do *almost anything*.\n\nA 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.\n\nSkills 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.\n\nA 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.\n\nSkill Markdown and bundled text resources use UTF-8. Skill-creator CLI and review utilities read and write text explicitly as UTF-8 so localized skills behave consistently across operating systems.\n\nUsers 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`.\n\nAn enabled skill's `allowed-tools` policy applies only after that skill is explicitly slash-activated or captured in the agent's active skill context after a `read_file` load. Merely enabling, advertising, or listing a skill in a custom agent or subagent `skills` allowlist does not reduce that agent's normal toolset; subagents use the same progressive discovery and activation policy as the lead agent. 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.\n\nWhen you install `.skill` archives through the Gateway, DeerFlow accepts standard space-separated `allowed-tools`, optional frontmatter metadata, and the Claude-compatible `argument-hint` field instead of rejecting otherwise valid external skills. YAML lists remain supported for `allowed-tools` and preserve exact runtime names. Exact portable spellings such as `WebFetch`, `WebSearch`, `Glob`, `Grep`, and `Read` map to DeerFlow's `web_fetch`, `web_search`, `glob`, `grep`, and `read_file` tools; lowercase or otherwise unknown scalar names remain unchanged so custom and MCP tools keep their exact runtime spelling. Parenthesized entries such as `Bash(tvly *)` are tokenized as one literal entry, including spaces, quoted text, and escaped parentheses, but remai",
  "bytes": 60000,
  "sha": "dc5c4fc2d285350397c3a8a096efac3cb824e0297eff3ef7ad987007c794ef51",
  "repo_slug": "bytedance/deer-flow",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/skl_bytedance_deer_flow_academic_paper_revie_61929a81/readme"
}