# DeerFlow Best Practices: Configuring ByteDance's Super-Agent Harness

> Discover DeerFlow best practices for ByteDance's Super Agent Harness. Optimize thread naming, file injection, and state management for seamless multi-turn conversations. Learn more now

- Repository: [Bytedance Inc./deer-flow](https://github.com/bytedance/deer-flow)
- Tags: best-practices
- Published: 2026-03-08

---

**DeerFlow best practices revolve around proper configuration of the TitleMiddleware for automatic thread naming, leveraging the UploadsMiddleware for seamless file injection, and utilizing the embedded Python client with persistent thread IDs to maintain state across multi-turn conversations.**

DeerFlow is a super-agent harness developed by ByteDance that orchestrates sub-agents, long-term memory, and sandboxed execution through an extensible skill system. Following DeerFlow best practices ensures optimal resource utilization, consistent thread management, and reliable file processing when building production AI applications. This guide references the actual `bytedance/deer-flow` source code to demonstrate authoritative configuration patterns and implementation details.

## Core Architecture and Configuration

Understanding the middleware stack and configuration loading mechanisms is essential for optimizing DeerFlow performance.

### Title Generation and Thread State Management

DeerFlow automatically generates concise thread titles after the first user-assistant exchange through the **TitleMiddleware**. Located in [`backend/src/agents/middlewares/title_middleware.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/agents/middlewares/title_middleware.py) (lines 24-92), this component stores titles in the **ThreadState** schema defined in [`backend/src/agents/thread_state.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/agents/thread_state.py) (lines 48-55). The thread state serves as a unified container for sandbox IDs, file uploads, artifacts, and viewed images across all middlewares.

Configuration defaults reside in [`backend/src/config/title_config.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/config/title_config.py) (lines 6-33), including parameters like `max_words` and `prompt_template`. The **AppConfig** loader in [`backend/src/config/app_config.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/config/app_config.py) (lines 81-84) reads these values from [`config.yaml`](https://github.com/bytedance/deer-flow/blob/main/config.yaml) at startup, resolving environment variables and injecting them into a singleton instance.

### Configuration Loading Patterns

The system uses a centralized configuration approach where `AppConfig.from_file` processes your [`config.yaml`](https://github.com/bytedance/deer-flow/blob/main/config.yaml) and populates global configuration objects. This singleton pattern means any changes to environment variables or configuration files reflect immediately in the embedded client without server restarts.

## Working with the Embedded Python Client

The **DeerFlowClient** in [`backend/src/client.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/client.py) provides a thin, in-process API that mirrors the HTTP gateway while maintaining agent caching for performance.

### Client Initialization and Caching

Always reuse the same client instance across calls to benefit from internal agent caching. The client reads the same configuration as the HTTP gateway, ensuring consistency between programmatic and REST API usage.

```python
from src.client import DeerFlowClient

# Re-use the same client across calls – the internal agent is cached.

client = DeerFlowClient()

```

### Streaming vs. One-Shot Execution

For simple synchronous interactions, use `DeerFlowClient.chat` (lines 66-89 in [`backend/src/client.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/client.py)), which streams internally and returns the final AI message. For interactive UIs, use `client.stream` to process partial outputs and tool invocations in real-time.

```python

# One-shot chat for simple use cases

response = client.chat(
    "Summarize the key takeaways from the 2024 State of AI report."
)
print(response)

# Streaming for rich UI updates

for event in client.stream(
    "Explain the differences between RAG and traditional search.",
    thread_id="demo-001",  # Persistent ID maintains context

):
    if event.type == "messages-tuple" and event.data["type"] == "ai":
        print(event.data["content"], end="", flush=True)

```

Supplying a consistent `thread_id` parameter ensures the check-pointer persists state including uploaded files and generated titles across conversation turns.

## File Handling and Middleware Integration

DeerFlow handles file uploads through middleware that automatically injects metadata into prompts, eliminating the need for manual file reference formatting.

### UploadsMiddleware Implementation

The **UploadsMiddleware** in [`backend/src/agents/middlewares/uploads_middleware.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/agents/middlewares/uploads_middleware.py) (lines 23-204) reads file metadata from `HumanMessage` objects, gathers historical uploads from the thread state, and prepends an `<uploaded_files>` block to the message. This makes files discoverable by tools like `read_file` without manual intervention.

### File Upload Workflow

Upload files before referencing them in prompts. The client automatically converts PDFs to markdown and registers them in the thread state.

```python

# Upload a PDF (automatically converts to markdown)

upload_res = client.upload_files(
    thread_id="demo-001",
    files=["./reports/2024_state_of_ai.pdf"]
)
print(upload_res["files"][0]["markdown_file"])

# The middleware automatically injects file context

summary = client.chat(
    "Provide a concise summary of the uploaded PDF.",
    thread_id="demo-001"
)

```

## Managing Skills and Toolsets

Skills extend DeerFlow's capabilities through modular toolsets loaded dynamically from the filesystem.

### Dynamic Skill Loading

The **Skill Loader** in [`backend/src/skills/loader.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/skills/loader.py) (lines 22-98) scans `skills/public` and `skills/custom` directories, parsing each [`SKILL.md`](https://github.com/bytedance/deer-flow/blob/main/SKILL.md) file and merging enablement states from [`extensions_config.json`](https://github.com/bytedance/deer-flow/blob/main/extensions_config.json). This hot-reloading mechanism allows runtime skill toggling without restarting the server.

### Runtime Skill Configuration

Use the embedded client to inspect and modify skill states programmatically:

```python

# List all loaded skills (enabled & disabled)

all_skills = client.list_skills()
print([s["name"] for s in all_skills["skills"]])

# Enable a custom skill at runtime

client.update_skill("my-awesome-skill", enabled=True)

```

The `update_skill` method rewrites [`extensions_config.json`](https://github.com/bytedance/deer-flow/blob/main/extensions_config.json), and subsequent calls to `load_skills` immediately reflect the change.

## Advanced Agent Configuration

Fine-tuning sub-agent behavior and memory persistence prevents resource exhaustion and optimizes latency.

### Sub-Agent Concurrency Control

When enabling sub-agents via `subagent_enabled=True`, the system respects the **SubAgentLimitMiddleware** in [`backend/src/agents/middlewares/subagent_limit_middleware.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/agents/middlewares/subagent_limit_middleware.py). By default, this caps concurrency at 3 simultaneous sub-agents to prevent runaway resource usage. Adjust this limit in the source if your use case requires higher parallelism, or disable sub-agents entirely for deterministic single-agent execution.

```python
client = DeerFlowClient(
    subagent_enabled=True,    # Enable delegation

    plan_mode=False,         # Keep simple turn-based flow

    thinking_enabled=True,
)

```

### Memory and Persistence Tuning

The **MemoryMiddleware** in [`backend/src/agents/middlewares/memory_middleware.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/agents/middlewares/memory_middleware.py) handles long-term memory injection. Disable the check-pointer in your configuration if you don't require cross-session context, reducing I/O overhead for stateless interactions. For persistent deployments, ensure your [`memory_config.yaml`](https://github.com/bytedance/deer-flow/blob/main/memory_config.yaml) properly configures the vector store backend.

Control title generation overhead by setting `enabled: false` in the `title` block of [`config.yaml`](https://github.com/bytedance/deer-flow/blob/main/config.yaml), or pass custom configurations directly to the client constructor for specific runs.

## Summary

- **Reuse the DeerFlowClient instance** to leverage internal agent caching and reduce initialization overhead.
- **Supply consistent `thread_id` values** when calling `chat()` or `stream()` to maintain file uploads, titles, and artifacts across conversation turns.
- **Upload files before referencing them** in prompts to allow `UploadsMiddleware` to automatically inject the `<uploaded_files>` block.
- **Manage skill states via `list_skills()` and `update_skill()`**, knowing that changes write to [`extensions_config.json`](https://github.com/bytedance/deer-flow/blob/main/extensions_config.json) and take effect immediately.
- **Respect the default sub-agent limit of 3 concurrent agents** defined in [`subagent_limit_middleware.py`](https://github.com/bytedance/deer-flow/blob/main/subagent_limit_middleware.py), or disable sub-agents for deterministic execution.
- **Configure title generation in [`title_config.py`](https://github.com/bytedance/deer-flow/blob/main/title_config.py)** or via [`config.yaml`](https://github.com/bytedance/deer-flow/blob/main/config.yaml) to control automatic thread naming behavior and reduce latency when disabled.
- **Enable check-pointing and MemoryMiddleware only when necessary** for cross-session persistence, otherwise disable to minimize I/O.

## Frequently Asked Questions

### How do I disable automatic title generation in DeerFlow?

Set `enabled: false` in the `title` block of your [`config.yaml`](https://github.com/bytedance/deer-flow/blob/main/config.yaml), or ensure the `title` configuration block is absent entirely. When disabled, the `TitleMiddleware._should_generate_title` method short-circuits and no title is stored in the `ThreadState`. You can also override this per-client instance by passing a custom configuration dictionary to `DeerFlowClient`.

### What is the default concurrency limit for sub-agents in DeerFlow?

The default limit is **3 concurrent sub-agents**, enforced by the `SubAgentLimitMiddleware` in [`backend/src/agents/middlewares/subagent_limit_middleware.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/agents/middlewares/subagent_limit_middleware.py). This prevents resource exhaustion when the super-agent spawns parallel research or computation tasks. You can modify this limit by editing the middleware source code if your infrastructure supports higher parallelism.

### How does DeerFlow handle file uploads across multiple conversation turns?

The `UploadsMiddleware` in [`backend/src/agents/middlewares/uploads_middleware.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/agents/middlewares/uploads_middleware.py) maintains a cumulative list of uploaded files in the `ThreadState`. When you provide a persistent `thread_id`, the middleware prepends an `<uploaded_files>` block containing both new and historical uploads to every `HumanMessage`, making all files accessible to tools like `read_file` throughout the conversation history.

### Where does DeerFlow store skill enablement configuration?

Skill enablement states are stored in [`extensions_config.json`](https://github.com/bytedance/deer-flow/blob/main/extensions_config.json) at the project root. The `load_skills` function in [`backend/src/skills/loader.py`](https://github.com/bytedance/deer-flow/blob/main/backend/src/skills/loader.py) (lines 22-98) reads this file alongside [`SKILL.md`](https://github.com/bytedance/deer-flow/blob/main/SKILL.md) manifests from `skills/public` and `skills/custom` directories. When you call `client.update_skill()`, the system rewrites this JSON file, and the next request immediately picks up the new state because `load_skills` reloads the configuration on every invocation.