Jesse A. Green / notebook

DeerFlow Administrator & Developer Guide

Generated May 2026 from bytedance/deer-flow at 259a684

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

1. Architecture Overview

DeerFlow is a full-stack AI agent platform built on LangGraph, FastAPI, and Next.js. It implements a lead agent orchestration pattern where a central agent delegates to sub-agents, tools, and skills to complete complex multi-step tasks. The platform supports pluggable LLM providers, sandboxed code execution, persistent memory, MCP server integration, a skills framework, and multi-channel IM integrations.

1.1 High-Level Architecture

┌──────────────────────────────────────────────────────────────────┐
│                         nginx (:2026)                            │
│   Reverse proxy — routes /api/* to gateway, LangGraph to :2024   │
├─────────────┬──────────────────┬─────────────────────────────────┤
│  Frontend   │  Gateway (:8001) │  LangGraph Server (:2024)       │
│  Next.js    │  FastAPI custom   │  LangGraph runtime (lead_agent) │
│  :3000      │  endpoints        │  checkpointer + store           │
├─────────────┴──────────────────┴─────────────────────────────────┤
│                  deerflow-harness (Python package)                │
│  Config │ Models │ Sandbox │ Skills │ Memory │ MCP │ Guardrails   │
├──────────────────────────────────────────────────────────────────┤
│              External Services & Infrastructure                   │
│  LLM APIs │ K8s Provisioner │ IM Channels │ Tracing (LangSmith)  │
└──────────────────────────────────────────────────────────────────┘

1.2 Component Inventory

Component Technology Port Purpose
Frontend Next.js 16, React 19, pnpm 10 3000 Web UI with chat, artifacts, settings
Gateway FastAPI (uvicorn) 8001 Custom API: models, MCP, memory, skills, uploads, agents, channels, runs
LangGraph Server langgraph dev 2024 Agent graph execution, checkpointing, state persistence
nginx nginx:alpine 2026 Reverse proxy, CORS, unified entry point
Provisioner FastAPI 8002 Kubernetes sandbox Pod lifecycle (optional)

1.3 Agent Architecture

lead_agent (LangGraph StateGraph)
├── Tool nodes (web_search, web_fetch, file ops, bash, image_search)
├── Sub-agents
│   ├── general-purpose — multi-step research and analysis
│   └── bash — shell command execution
├── Skills (15+ built-in, user-extensible)
├── MCP tool nodes (stdio/sse/streamable_http servers)
├── ACP agents (Claude Code, Codex CLI via subprocess)
└── Middleware
    ├── TitleMiddleware — auto-generate conversation titles
    ├── SummarizationMiddleware — compress long context
    └── MemoryMiddleware — persistent fact extraction

The lead agent is registered in backend/langgraph.json as deerflow.agents:make_lead_agent. All custom agents route through make_lead_agent with an agent_name injected into configurable, which loads a per-agent SOUL.md and config.yaml from the agents/<name>/ directory.


2. System Requirements

2.1 Backend Requirements

Requirement Version
Python >= 3.12
Package manager uv (recommended)
OS Linux, macOS, Windows (WSL recommended for Docker)
Node.js >= 18 (for frontend)
pnpm 10.26.2

2.2 Python Dependencies (Core)

From pyproject.toml (deerflow-harness):

Package Version Constraint Purpose
langgraph >= 1.0.6, < 1.0.10 Agent graph runtime
langgraph-api >= 0.7.0, < 0.8.0 LangGraph Platform compatibility
langgraph-runtime-inmem >= 0.22.1 In-memory runtime
langchain >= 1.2.3 LLM framework
langchain-openai >= 1.1.7 OpenAI provider
langchain-anthropic >= 1.3.4 Anthropic provider
langchain-deepseek >= 1.0.1 DeepSeek provider
langchain-google-genai >= 4.2.1 Google Gemini provider
pydantic >= 2.12.5 Config models
kubernetes >= 30.0.0 K8s provisioner client
agent-client-protocol >= 0.4.0 ACP agent integration
agent-sandbox >= 0.0.19 Sandbox abstraction
langchain-mcp-adapters >= 0.1.0 MCP server integration
langgraph-checkpoint-sqlite >= 3.0.3 SQLite checkpointer

Optional extras:

Extra Package Purpose
ollama langchain-ollama >= 0.3.0 Ollama native API support
pymupdf pymupdf4llm >= 0.0.17 Better PDF-to-Markdown conversion

2.3 Frontend Dependencies (Key)

Package Version Purpose
next 16 React framework with App Router
react 19 UI library
@langchain/langgraph-sdk latest LangGraph client SDK
@xyflow/react latest Flow diagram rendering
better-auth latest Authentication
nextra latest Documentation site
streamdown latest Streaming markdown renderer
codemirror latest Code editor

3. Configuration Reference

DeerFlow uses two configuration files plus environment variables:

File Format Purpose
config.yaml YAML Primary configuration: models, tools, sandbox, memory, channels
extensions_config.json JSON MCP server definitions, skill state overrides
.env dotenv API keys and secrets

Important

Copy config.example.yaml to config.yaml before first run. The setup wizard (make setup or python scripts/setup_wizard.py) generates a minimal working config interactively.

3.1 Configuration Resolution

  1. DEER_FLOW_CONFIG_PATH environment variable (highest priority)
  2. config.yaml in the current working directory
  3. config.yaml at the repository root

For extensions: DEER_FLOW_EXTENSIONS_CONFIG_PATH or extensions_config.json in the same search order.

3.2 Config Version

config_version: 7   # Schema version — bump triggers make config-upgrade

Run make config-upgrade after upgrading DeerFlow to merge new fields into your local config.

3.3 Models Configuration

Each model entry defines an LLM provider:

models:
  - name: gpt-4o                          # Internal identifier
    display_name: GPT-4o                   # Shown in UI
    use: langchain_openai:ChatOpenAI       # Python class path
    model: gpt-4o                          # Provider model name
    api_key: $OPENAI_API_KEY               # $VAR resolves from env
    base_url: https://api.openai.com/v1    # Optional override
    request_timeout: 600.0
    max_retries: 2
    max_tokens: 4096
    temperature: 0.7
    supports_vision: true
    supports_thinking: true
    supports_reasoning_effort: true
    when_thinking_enabled:                 # Applied when thinking toggle is on
      extra_body:
        thinking:
          type: enabled
    when_thinking_disabled:
      extra_body:
        thinking:
          type: disabled

Supported providers and their use class paths:

Provider use Path Notes
OpenAI langchain_openai:ChatOpenAI Standard; also works for OpenRouter
Anthropic langchain_anthropic:ChatAnthropic Requires max_tokens
DeepSeek deerflow.models.patched_deepseek:PatchedChatDeepSeek Patched for thinking
Google Gemini (native) langchain_google_genai:ChatGoogleGenerativeAI Uses gemini_api_key
Gemini (OpenAI-compat) deerflow.models.patched_openai:PatchedChatOpenAI Preserves thought_signature
Ollama (native) langchain_ollama:ChatOllama Install extra: uv pip install 'deerflow-harness[ollama]'
vLLM deerflow.models.vllm_provider:VllmChatModel Self-hosted; Qwen-style reasoning toggle
MiniMax deerflow.models.patched_minimax:PatchedChatMiniMax Temperature must be in (0.0, 1.0]
Claude Code OAuth deerflow.models.claude_provider:ClaudeChatModel Uses local ~/.claude credentials
Codex CLI deerflow.models.openai_codex_provider:CodexChatModel Uses ~/.codex/auth.json

Warning

For Ollama models, use langchain_ollama:ChatOllama (native API), not the OpenAI-compatible endpoint. The /v1/chat/completions endpoint drops or flattens reasoning content.

3.4 Tools Configuration

Tools are organized into groups for access control:

tool_groups:
  - name: web
  - name: file:read
  - name: file:write
  - name: bash

tools:
  - name: web_search
    group: web
    use: deerflow.community.ddg_search.tools:web_search_tool  # No API key needed
    max_results: 5

  - name: web_fetch
    group: web
    use: deerflow.community.jina_ai.tools:web_fetch_tool
    timeout: 10

  - name: bash
    group: bash
    use: deerflow.sandbox.tools:bash_tool

Search providers: DuckDuckGo (free, default), Tavily, InfoQuest, Exa, Firecrawl.

Web fetch providers: Jina AI (free, default), Exa, InfoQuest, Firecrawl.

File operation tools: ls, read_file, glob, grep, write_file, str_replace.

Tip

Only one web_search and one web_fetch provider can be active at a time. Comment out alternatives before enabling a new one.

3.5 Sandbox Configuration

Three sandbox modes are available:

Mode use Path Isolation Requirements
Local (default) deerflow.sandbox.local:LocalSandboxProvider None (host process) None
AIO Container deerflow.community.aio_sandbox:AioSandboxProvider Docker / Apple Container Docker or Apple Container runtime
Provisioner (K8s) deerflow.community.aio_sandbox:AioSandboxProvider + provisioner_url Kubernetes Pod per sandbox K8s cluster + provisioner service
# Local sandbox (default)
sandbox:
  use: deerflow.sandbox.local:LocalSandboxProvider
  allow_host_bash: false          # Set true only for trusted single-user
  bash_output_max_chars: 20000
  read_file_output_max_chars: 50000
  ls_output_max_chars: 20000
  # mounts:
  #   - host_path: /home/user/project
  #     container_path: /mnt/project
  #     read_only: true

Caution

allow_host_bash: true gives the agent unrestricted shell access on the host. Only enable for fully trusted, single-user local workflows. For multi-user or production use, deploy the AIO Container or Kubernetes sandbox.

3.6 Subagents Configuration

subagents:
  timeout_seconds: 900           # Default 15 min
  # max_turns: 120               # Global max-turn override
  agents:
    general-purpose:
      timeout_seconds: 1800      # 30 min for complex tasks
      max_turns: 160
      # model: qwen3:32b         # Override model
    bash:
      timeout_seconds: 300       # 5 min
      max_turns: 80

Subagents inherit the lead agent's model by default. Set model to use a cheaper/faster model for specific agents.

3.7 Memory Configuration

memory:
  enabled: true
  storage_path: memory.json      # Relative to backend/
  debounce_seconds: 30           # Queue delay before processing
  model_name: null               # null = default model
  max_facts: 100
  fact_confidence_threshold: 0.7
  injection_enabled: true        # Inject into system prompt
  max_injection_tokens: 2000

Memory uses a debounced queue: fact extraction requests are batched and processed after debounce_seconds of inactivity. Facts below fact_confidence_threshold are discarded.

3.8 Summarization Configuration

Automatic context compression when conversations approach token limits:

summarization:
  enabled: true
  model_name: null               # Use a lightweight model for cost savings
  trigger:
    - type: tokens
      value: 15564               # Summarize when token count reached
    # - type: messages
    #   value: 50
    # - type: fraction
    #   value: 0.8               # 80% of model max input
  keep:
    type: messages
    value: 10                    # Retain 10 most recent messages
  trim_tokens_to_summarize: 15564

3.9 Checkpointer Configuration

State persistence for multi-turn conversations:

Type Persistence Use Case
memory In-process only (default) Development, ephemeral
sqlite File-based Single-process, survives restarts
postgres PostgreSQL Multi-process, production
checkpointer:
  type: sqlite
  connection_string: checkpoints.db

# PostgreSQL:
# checkpointer:
#   type: postgres
#   connection_string: postgresql://user:password@localhost:5432/deerflow

Note

The checkpointer setting applies to the embedded DeerFlowClient. The LangGraph Server manages its own persistence separately via server infrastructure.

3.10 IM Channels Configuration

All channels use outbound connections (WebSocket or polling) and require no public IP:

channels:
  langgraph_url: http://localhost:2024
  gateway_url: http://localhost:8001

  session:                       # Default session settings
    assistant_id: lead_agent
    context:
      thinking_enabled: true
      is_plan_mode: false

  feishu:
    enabled: false
    app_id: $FEISHU_APP_ID
    app_secret: $FEISHU_APP_SECRET

  slack:
    enabled: false
    bot_token: $SLACK_BOT_TOKEN
    app_token: $SLACK_APP_TOKEN  # Socket Mode
    allowed_users: []            # Empty = allow all

  telegram:
    enabled: false
    bot_token: $TELEGRAM_BOT_TOKEN

  wechat:
    enabled: false
    bot_token: $WECHAT_BOT_TOKEN
    ilink_bot_id: $WECHAT_ILINK_BOT_ID
    qrcode_login_enabled: true

  wecom:
    enabled: false
    bot_id: $WECOM_BOT_ID
    bot_secret: $WECOM_BOT_SECRET

Per-channel and per-user session overrides are supported. Set session.assistant_id to a custom agent name for IM-specific behavior.

3.11 MCP Server Configuration

Define MCP servers in extensions_config.json:

{
  "mcpServers": {
    "filesystem": {
      "enabled": true,
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/files"],
      "env": {},
      "description": "Filesystem access"
    },
    "github": {
      "enabled": false,
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" }
    }
  }
}

Supported transport types: stdio, sse, streamable_http. Environment variables in env values prefixed with $ resolve from the host environment.

Tool search (deferred loading): When many MCP servers expose large tool sets, enable deferred loading to reduce context:

tool_search:
  enabled: true   # Tools listed by name only; loaded on demand via tool_search

3.12 Guardrails Configuration

Pre-execution authorization for tool calls:

# Option 1: Built-in allowlist
guardrails:
  enabled: true
  provider:
    use: deerflow.guardrails.builtin:AllowlistProvider
    config:
      denied_tools: ["bash", "write_file"]

# Option 2: OAP (Open Agent Passport) standard
guardrails:
  enabled: true
  provider:
    use: aport_guardrails.providers.generic:OAPGuardrailProvider

3.13 Circuit Breaker

Prevents retry storms when an LLM provider is down:

circuit_breaker:
  failure_threshold: 5      # Consecutive failures before opening
  recovery_timeout_sec: 60  # Wait before half-open probe

3.14 Additional Configuration

Feature Config Key Default Description
Title generation title.enabled true Auto-generate conversation titles
Title max length title.max_words / title.max_chars 6 / 60 Title constraints
Token usage tracking token_usage.enabled false Record input/output tokens per call
Log level log_level info Options: debug, info, warning, error
Agents API agents_api.enabled false HTTP management of custom agent SOUL/config
Skill evolution skill_evolution.enabled false Agent can create skills in skills/custom/
Skills path skills.path ../skills Host path to skills directory
Skills container path skills.container_path /mnt/skills Sandbox-visible path

4. Environment Variables Reference

4.1 Backend Environment Variables

Variable Default Purpose
DEER_FLOW_CONFIG_PATH (none) Override config.yaml location
DEER_FLOW_EXTENSIONS_CONFIG_PATH (none) Override extensions_config.json location
DEER_FLOW_HOME (none) Base directory for runtime data (.deer-flow/)
DEER_FLOW_HOST_BASE_DIR (none) Host-side base dir for sandbox volume mounts
DEER_FLOW_HOST_SKILLS_PATH (none) Host-side skills dir for sandbox mounts
DEER_FLOW_SANDBOX_HOST (none) Hostname for sandbox access from containers
GATEWAY_HOST 0.0.0.0 Gateway bind address
GATEWAY_PORT 8001 Gateway bind port
CORS_ORIGINS http://localhost:3000 Comma-separated allowed CORS origins

4.2 Frontend Environment Variables

Variable Default Purpose
NEXT_PUBLIC_BACKEND_BASE_URL (none) Gateway API URL for client-side requests
NEXT_PUBLIC_LANGGRAPH_BASE_URL (none) LangGraph server URL
NEXT_PUBLIC_STATIC_WEBSITE_ONLY (none) Run as static documentation site
BETTER_AUTH_SECRET (none) Auth signing secret
BETTER_AUTH_GITHUB_CLIENT_ID (none) GitHub OAuth client ID
BETTER_AUTH_GITHUB_CLIENT_SECRET (none) GitHub OAuth client secret
SKIP_ENV_VALIDATION (none) Bypass env validation at build time

4.3 Provisioner Environment Variables

Variable Default Purpose
K8S_NAMESPACE deer-flow Kubernetes namespace for sandbox Pods
SANDBOX_IMAGE enterprise-public-cn-beijing.cr.volces.com/... Container image for sandbox Pods
SKILLS_HOST_PATH /skills Host path for K8s HostPath volume (skills)
THREADS_HOST_PATH /.deer-flow/threads Host path for thread data
SKILLS_PVC_NAME (none) PVC name for skills (replaces hostPath)
USERDATA_PVC_NAME (none) PVC name for user data (replaces hostPath)
KUBECONFIG_PATH /root/.kube/config Path to kubeconfig inside container
NODE_HOST host.docker.internal Hostname to reach K8s NodePort services
K8S_API_SERVER (none) Override K8s API server URL

4.4 LLM Provider API Keys

Variable Provider
OPENAI_API_KEY OpenAI
ANTHROPIC_API_KEY Anthropic
DEEPSEEK_API_KEY DeepSeek
GEMINI_API_KEY Google Gemini
OPENROUTER_API_KEY OpenRouter
VLLM_API_KEY vLLM (self-hosted)
TAVILY_API_KEY Tavily search
EXA_API_KEY Exa search
FIRECRAWL_API_KEY Firecrawl search
MINIMAX_API_KEY MiniMax

4.5 IM Channel Secrets

Variable Channel
FEISHU_APP_ID / FEISHU_APP_SECRET Feishu/Lark
SLACK_BOT_TOKEN / SLACK_APP_TOKEN Slack (Socket Mode)
TELEGRAM_BOT_TOKEN Telegram
WECHAT_BOT_TOKEN / WECHAT_ILINK_BOT_ID WeChat
WECOM_BOT_ID / WECOM_BOT_SECRET WeCom

4.6 Observability

Variable Provider
LANGSMITH_API_KEY (or LANGCHAIN_API_KEY) LangSmith tracing
LANGFUSE_HOST / LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEY Langfuse tracing

5. Deployment & Scaling

5.1 Local Development (make commands)

# First-time setup
make setup                # Interactive wizard: LLM provider, search, sandbox

# Start services
cd backend && uv sync && PYTHONPATH=. uv run uvicorn app.gateway.app:app \
    --host 0.0.0.0 --port 8001 --reload
cd backend && uv run langgraph dev --no-browser --host 0.0.0.0 --port 2024

# Frontend
cd frontend && pnpm install && pnpm run dev

5.2 Docker Compose Development

# Set project root for volume mounts
export DEER_FLOW_ROOT=$(pwd)

# Start all services
docker compose -f docker/docker-compose-dev.yaml up --build

# Access at http://localhost:2026

Services started:

Service Container Name Exposed Port Health Check
nginx deer-flow-nginx 2026 —
frontend deer-flow-frontend (internal 3000) —
gateway deer-flow-gateway (internal 8001) —
langgraph deer-flow-langgraph (internal 2024) —
provisioner deer-flow-provisioner (internal 8002) curl http://localhost:8002/health

Docker networking: All services communicate on a bridge network (192.168.200.0/24). For inter-container references, use service names (gateway:8001, langgraph:2024).

Important

On Docker Compose, set DEER_FLOW_ROOT to the absolute path of the project root before starting. Volume mounts for skills, config, and thread data depend on this variable.

5.3 Docker Volume Strategy

Named volumes preserve Python virtual environments across restarts:

Volume Purpose
gateway-venv Gateway .venv (prevents host mount shadowing)
langgraph-venv LangGraph server .venv
gateway-uv-cache uv cache (avoids symlink failures on macOS)
langgraph-uv-cache uv cache for LangGraph

5.4 Kubernetes Sandbox Provisioner

For production sandbox isolation, the provisioner creates per-sandbox Pods:

┌────────────┐  HTTP   ┌─────────────┐  K8s API  ┌──────────────┐
│  backend   │ ──────▸ │ provisioner │ ────────▸ │  K8s cluster │
│            │         │ :8002       │           │              │
└────────────┘         └─────────────┘           └──────┬───────┘
                                                        │ creates
                       ┌─────────────┐          ┌───────▼──────┐
                       │   backend   │ ───────▸ │ sandbox Pods │
                       │             │ NodePort  │              │
                       └─────────────┘          └──────────────┘

Provisioner API:

Method Path Purpose
POST /api/sandboxes Create sandbox Pod + Service
DELETE /api/sandboxes/{sandbox_id} Destroy sandbox
GET /api/sandboxes/{sandbox_id} Get sandbox status & URL
GET /api/sandboxes List all sandboxes
GET /health Health check

For production, use PVC-backed storage instead of hostPath:

environment:
  - SKILLS_PVC_NAME=deer-flow-skills-pvc
  - USERDATA_PVC_NAME=deer-flow-userdata-pvc

5.5 nginx Routing

nginx handles all external traffic on port 2026:

  • /api/* requests → gateway (:8001)
  • LangGraph requests → LangGraph server (:2024), controlled by LANGGRAPH_UPSTREAM and LANGGRAPH_REWRITE env vars
  • All other requests → frontend (:3000)
  • CORS is handled at the nginx layer (not FastAPI middleware)

6. Operations

6.1 Gateway API Endpoints

The Gateway exposes 13 router groups:

Router Mount Path Tag Purpose
models /api/models models Query available LLM models and configs
mcp /api/mcp mcp MCP server configuration management
memory /api/memory memory Global memory data access
skills /api/skills skills Skills listing and enable/disable
artifacts /api/threads/{thread_id}/artifacts artifacts Thread file artifacts
uploads /api/threads/{thread_id}/uploads uploads File upload management
threads /api/threads/{thread_id} threads Thread-local filesystem cleanup
agents /api/agents agents Custom agent CRUD
suggestions /api/threads/{thread_id}/suggestions suggestions Follow-up question generation
channels /api/channels channels IM channel status and management
assistants_compat (LangGraph stub) assistants-compat LangGraph Platform assistants compatibility
thread_runs (LangGraph compat) runs Thread-scoped run lifecycle
runs (LangGraph compat) runs Stateless runs (stream/wait without thread)

Health endpoint: GET /health returns {"status": "healthy", "service": "deer-flow-gateway"}.

API documentation: Available at /docs (Swagger UI) and /redoc (ReDoc) when the gateway is running.

6.2 Runtime Singletons

The gateway initializes four singletons during startup via the langgraph_runtime context manager:

Singleton Class Purpose
stream_bridge StreamBridge SSE event distribution to clients
checkpointer (async provider) State persistence
store (async provider) Thread metadata persistence
run_manager RunManager Run lifecycle, conflict detection

If any singleton is missing at request time, the corresponding getter raises HTTP 503.

6.3 Run Lifecycle

Client POST /runs/stream (or /threads/{id}/runs/stream)
  → RunManager.create_or_reject()     # 409 on conflict
  → resolve_agent_factory()           # Always make_lead_agent
  → build_run_config()                # Thread ID, agent_name, context overrides
  → asyncio.create_task(run_agent())  # Background execution
  → SSE consumer yields frames       # event: data: id: format
  → On disconnect:
      cancel mode → abort background task
      continue mode → task runs, events discarded

Context overrides in run requests: The context field carries DeerFlow-specific keys:

Key Type Purpose
model_name string Override LLM model for this run
mode string Agent mode
thinking_enabled bool Toggle thinking/reasoning
reasoning_effort string Reasoning effort level
is_plan_mode bool Enable plan mode with todo lists
subagent_enabled bool Allow sub-agent delegation
max_concurrent_subagents int Concurrency limit
agent_name string Custom agent selection
is_bootstrap bool Bootstrap mode flag

6.4 Filesystem Layout

backend/.deer-flow/                   # DEER_FLOW_HOME
├── memory.json                       # Global memory store
├── USER.md                           # Global user profile
├── agents/                           # Custom agents
│   └── {agent-name}/
│       ├── config.yaml               # Agent config (name, model, skills)
│       ├── SOUL.md                    # Agent personality/values
│       └── memory.json               # Per-agent memory
├── threads/
│   └── {thread-id}/
│       └── user-data/
│           ├── work/                  # Sandbox working directory
│           ├── uploads/               # User-uploaded files
│           └── outputs/               # Agent-generated artifacts
└── checkpoints.db                    # SQLite checkpointer (if configured)

Thread IDs are validated against pattern ^[A-Za-z0-9_\-]+$. Path traversal is explicitly blocked with a 403 response.

6.5 Observability & Tracing

DeerFlow supports two tracing providers that can run simultaneously:

Provider Required Variables Auto-Detection
LangSmith LANGSMITH_API_KEY (or LANGCHAIN_API_KEY) Enabled when key is set
Langfuse LANGFUSE_HOST, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY Enabled when all three are set

Configure via config.yaml:

tracing:
  langsmith:
    enabled: true
  langfuse:
    enabled: true

Validation runs at startup — missing keys for enabled providers raise ValueError with specific guidance.

6.6 Logging

log_level: info    # debug | info | warning | error

Logs use format: %(asctime)s - %(name)s - %(levelname)s - %(message)s. Gateway and provisioner each configure independent logging.


7. Security

7.1 Sandbox Isolation

Level Isolation Risk
Local None — runs as the host process Agent has full host access when allow_host_bash: true
AIO Container Docker container per sandbox Container escape = host compromise
K8s Provisioner Dedicated Pod per sandbox Best isolation; use PVCs and NetworkPolicy

Caution

LocalSandboxProvider with allow_host_bash: true is not a security boundary. The agent can execute arbitrary commands on the host. Use only in fully trusted, single-user environments.

7.2 Path Traversal Protection

The Paths.resolve_virtual_path() method validates all sandbox file access:

  • Paths must start with a recognized prefix (/mnt/user-data/, /mnt/skills/)
  • Path traversal (../) is detected and rejected with HTTP 403
  • Thread IDs are validated against ^[A-Za-z0-9_\-]+$

7.3 Authentication

  • Frontend: better-auth with optional GitHub OAuth (BETTER_AUTH_GITHUB_CLIENT_ID)
  • Gateway API: No built-in auth layer — CORS handled by nginx. The agents_api is disabled by default
  • IM Channels: Each channel has its own auth (bot tokens, app secrets). allowed_users lists restrict access

7.4 Agent API Security

The agents_api.enabled flag (default: false) controls HTTP access to custom agent management. When enabled, it exposes read/write access to SOUL.md, config.yaml, and USER.md for all agents.

Warning

Only enable agents_api when the gateway is behind a trusted, authenticated admin boundary. The API has no built-in auth — anyone who can reach the gateway can modify agent configurations.

7.5 ACP Agent Permissions

ACP agents (Claude Code, Codex CLI) run as subprocesses. auto_approve_permissions: false (default) denies all permission requests. Set to true only for trusted agents.

7.6 Guardrails

When guardrails.enabled: true, every tool call passes through the configured provider before execution. The built-in AllowlistProvider supports denied_tools to block specific tools (e.g., bash, write_file). External OAP-compliant providers enable policy-based authorization.


8. Custom Agents

8.1 Creating a Custom Agent

Create a directory under agents/ (inside DEER_FLOW_HOME):

agents/my-agent/
├── config.yaml    # Required
└── SOUL.md        # Optional personality/values prompt

config.yaml:

name: my-agent
description: A specialized agent for data analysis
model: gpt-4o              # Override default model (optional)
tool_groups:                # Restrict available tool groups (optional)
  - web
  - file:read
skills:                     # Restrict loaded skills (optional)
  - crawl_and_report
  # null or omitted = all skills; [] = no skills

SOUL.md: Injected into the lead agent's system prompt when agent_name matches. Define personality, values, and behavioral guardrails.

8.2 Agent Name Rules

  • Pattern: ^[A-Za-z0-9-]+$ (letters, digits, hyphens only)
  • Normalized to lowercase with underscores replaced by hyphens
  • Invalid names raise ValueError

8.3 Per-Channel Agent Routing

IM channels can specify a custom agent via session.assistant_id. Per-user overrides are supported:

channels:
  wechat:
    session:
      assistant_id: mobile-agent
      users:
        "123456789":
          assistant_id: vip-agent

9. Skills System

9.1 Overview

Skills are structured markdown files in skills/ that the lead agent can invoke. They define reusable workflows (e.g., "crawl and generate report", "create podcast script").

  • Built-in skills: skills/public/ (15+ included)
  • Custom skills: skills/custom/ (user-created)
  • Skill evolution: When skill_evolution.enabled: true, the agent can autonomously create and improve skills in skills/custom/

9.2 Skill Access Control

Per-agent skill restrictions in agents/<name>/config.yaml:

skills value Behavior
null / omitted Load all globally enabled skills
[] (empty list) Disable all skills
["skill-name"] Load only specified skills

Skill enable/disable state can also be managed via extensions_config.json under the skills key and through the /api/skills gateway endpoint.


10. Troubleshooting

10.1 Common Errors

Error Cause Resolution
Failed to load configuration during gateway startup Missing or invalid config.yaml Run make setup or copy config.example.yaml
Config file specified by DEER_FLOW_CONFIG_PATH not found DEER_FLOW_CONFIG_PATH points to nonexistent file Verify the path; unset to use default resolution
Model {name} not found in config Requested model not in models: list Add model entry to config.yaml
Model {name} does not support thinking supports_thinking not set Add supports_thinking: true to model config
Environment variable {VAR} not found for config value $VAR in config but not in env Set the variable in .env or shell
Extensions config file is not valid JSON Malformed extensions_config.json Validate JSON syntax
LangSmith tracing enabled but API key not set Tracing enabled without credentials Set LANGSMITH_API_KEY or disable tracing
Stream bridge not available (503) Runtime not initialized Check gateway startup logs for initialization errors
Run manager not available (503) Runtime not initialized Same as above
Invalid assistant_id (ValueError) Special characters in agent name Use only letters, digits, and hyphens
Agent directory not found Custom agent path missing Create agents/<name>/ with config.yaml
Access denied: path traversal detected (403) ../ in file path Use absolute virtual paths without traversal
Codex CLI credential not found Missing ~/.codex/auth.json Run codex auth to authenticate

10.2 Docker Troubleshooting

Issue Resolution
uv sync fails on startup Container recreates .venv and retries once automatically. If persistent, run docker compose down -v to clear named volumes
Frontend hot-reload not working Ensure WATCHPACK_POLLING=true is set (default in compose file)
Gateway can't reach LangGraph Verify both are on deer-flow-dev network; use service name langgraph:2024
Provisioner health check failing Ensure kubeconfig is mounted and K8s cluster is reachable
macOS uv symlink failures Named volumes (gateway-uv-cache) avoid this — do not bind-mount the uv cache

10.3 Debugging

Interactive debug mode with breakpoints:

cd backend && PYTHONPATH=. uv run python debug.py

This starts a REPL-style session with the lead agent. Configure model and thread ID in debug.py.


11. Developer Internals

11.1 Module Reference

Package structure:

backend/
├── app/gateway/              # FastAPI gateway application
│   ├── app.py                # App factory, lifespan, router mounting
│   ├── config.py             # GatewayConfig (host, port, CORS)
│   ├── deps.py               # Runtime singletons (StreamBridge, RunManager, etc.)
│   ├── services.py           # Run lifecycle, SSE formatting, input normalization
│   ├── path_utils.py         # Virtual path resolution
│   └── routers/              # 13 router modules
├── packages/harness/deerflow/
│   ├── agents/               # Lead agent, subagents, checkpointer
│   ├── config/               # 22 config modules (Pydantic models)
│   ├── models/               # LLM provider wrappers
│   │   ├── factory.py        # create_chat_model() — model instantiation
│   │   ├── claude_provider.py    # ClaudeChatModel (OAuth)
│   │   ├── openai_codex_provider.py  # CodexChatModel
│   │   ├── patched_deepseek.py   # PatchedChatDeepSeek
│   │   ├── patched_minimax.py    # PatchedChatMiniMax
│   │   ├── patched_openai.py     # PatchedChatOpenAI (thought_signature)
│   │   ├── vllm_provider.py      # VllmChatModel
│   │   └── credential_loader.py  # Claude Code + Codex CLI auth loading
│   ├── community/            # Search/fetch provider implementations
│   ├── guardrails/           # AllowlistProvider, guardrail interface
│   ├── mcp/                  # MCP tool initialization
│   ├── runtime/              # StreamBridge, RunManager, RunRecord, RunStatus
│   ├── sandbox/              # LocalSandboxProvider, tool implementations
│   └── utils/                # file_conversion, network, readability
├── debug.py                  # Interactive agent debugger
├── langgraph.json            # LangGraph server configuration
└── ruff.toml                 # Linter config (line-length: 240, py312)

11.2 Key Classes

Class Module Purpose
AppConfig config/app_config.py Central config — models, tools, sandbox, all subsystems
ExtensionsConfig config/extensions_config.py MCP servers, skill state
GatewayConfig gateway/config.py Gateway host/port/CORS
Paths config/paths.py 20+ path resolution methods (thread dirs, virtual paths)
SandboxConfig config/sandbox_config.py Sandbox provider + mounts + truncation limits
SubagentsAppConfig config/subagents_config.py Per-agent timeout/model/max_turns overrides
StreamBridge runtime/ Per-run SSE event distribution
RunManager runtime/ Run lifecycle, conflict detection (409 on concurrent)
RunRecord runtime/ Run state: pending → running → completed/cancelled
AgentConfig config/agents_config.py Custom agent definition (name, model, skills, tool_groups)
ACPAgentConfig config/acp_config.py External ACP agent subprocess config
MemoryConfig config/memory_config.py Memory system settings
SummarizationConfig config/summarization_config.py Context compression triggers and retention
CircuitBreakerConfig config/app_config.py LLM call failure circuit breaker
TracingConfig config/tracing_config.py LangSmith + Langfuse tracing

11.3 Configuration Loading Chain

AppConfig.from_file(config_path)
  → resolve_config_path()           # DEER_FLOW_CONFIG_PATH → cwd → repo root
  → yaml.safe_load()
  → resolve_env_variables()         # Recursive $VAR substitution
  → Load subsystem configs:
      load_memory_config_from_dict()
      load_summarization_config_from_dict()
      load_title_config_from_dict()
      load_subagents_config_from_dict()
      load_checkpointer_config_from_dict()
      load_guardrails_config_from_dict()
      load_acp_config_from_dict()
      load_agents_api_config_from_dict()
      load_stream_bridge_config_from_dict()
      load_tool_search_config_from_dict()

Environment variable resolution is recursive: any string value starting with $ is replaced with the corresponding environment variable. Missing variables raise ValueError.

11.4 Model Factory

create_chat_model(name, thinking_enabled) in models/factory.py:

  1. Looks up model name in AppConfig.models
  2. Resolves the use class path via resolve_variable()
  3. Applies when_thinking_enabled or when_thinking_disabled overrides
  4. Instantiates the LangChain BaseChatModel subclass

11.5 Credential Loading (Zero-Config Auth)

Two zero-config auth providers use local CLI credentials:

Provider Credential Source Env Override
Claude Code OAuth ~/.claude/credentials.json CLAUDE_CODE_CREDENTIALS_PATH, CLAUDE_CODE_OAUTH_TOKEN, ANTHROPIC_AUTH_TOKEN
Codex CLI ~/.codex/auth.json CODEX_AUTH_PATH

ClaudeCodeCredential tracks token expiry via is_expired(). Docker containers mount ~/.claude and ~/.codex read-only for auto-auth.

11.6 Code Conventions

Convention Value
Python version 3.12+
Line length 240 (ruff)
Lint rules E, F, I, UP (ruff)
Import sorting isort, first-party: deerflow, app
Quote style Double
Indent style Spaces
Config models Pydantic v2 BaseModel
Async asyncio throughout (gateway, runtime, providers)

11.7 Testing

  • Backend linting: ruff check with ruff.toml configuration
  • Frontend: pnpm-based test and lint commands
  • Unit tests: Located alongside source in standard pytest layout
  • API tests: Reference in frontend/tests/unit/core/api/
  • Debug mode: backend/debug.py for interactive agent testing with breakpoints

11.8 Known Issues (from GitHub)

Issue Description Status
#2293 Error 400 during normal operation Open
#2302 Event loop closed unexpectedly Open
#2255 Duplicate tool calls generated Open
#2203 JSON parse errors in responses Open
#2262 File upload failures Open
#2303 Conversation switching interrupts running tasks Open
#2304 Loop detection triggering incorrectly Open
#2297 Docker container cannot access host ports Open

12. Quick Reference

12.1 Key Files

File Purpose
config.yaml Primary config (models, tools, sandbox, memory, channels)
config.example.yaml Full config reference with all options documented
extensions_config.json MCP server definitions
.env API keys and secrets
backend/langgraph.json LangGraph server config (graph entry point, checkpointer)
backend/ruff.toml Python linter configuration
docker/docker-compose-dev.yaml Docker Compose development environment
docker/nginx/nginx.conf nginx reverse proxy configuration (template)

12.2 Common Commands

Task Command
First-time setup make setup
Start gateway cd backend && PYTHONPATH=. uv run uvicorn app.gateway.app:app --host 0.0.0.0 --port 8001 --reload
Start LangGraph cd backend && uv run langgraph dev --no-browser --host 0.0.0.0 --port 2024
Start frontend cd frontend && pnpm run dev
Docker Compose up docker compose -f docker/docker-compose-dev.yaml up --build
Config upgrade make config-upgrade
Debug agent cd backend && PYTHONPATH=. uv run python debug.py
Install Ollama extra cd backend && uv pip install 'deerflow-harness[ollama]'

12.3 Port Map

Port Service Protocol
2024 LangGraph Server HTTP/SSE
2026 nginx (unified entry) HTTP
3000 Frontend (Next.js dev) HTTP
8001 Gateway API HTTP
8002 Sandbox Provisioner HTTP
11434 Ollama (if local) HTTP