Jesse A. Green / notebook

OpenManus Administrator & Developer Guide

Generated June 2026 from FoundationAgents/OpenManus at 52a13f2

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.

OpenManus is an async-first, Python framework for building general-purpose LLM agents (version 0.1.0, MIT-licensed, by contributors from the MetaGPT community). Its architecture is a layered agent class hierarchy that runs a ReAct (reason → act) loop over a pluggable tool collection, backed by a provider-agnostic LLM client and configured entirely through TOML. This guide is the operational and developer reference: architecture, configuration, deployment, security, internals, and improvement notes.

Note

OpenManus has no server-side persistence, no database, and no built-in authentication. It is a locally run agent runtime. Its operational surface is: an LLM API connection, a set of tools that touch the local machine (shell, Python, files, browser), and optional MCP / Daytona / A2A integrations. Plan security accordingly — see §5.


Table of Contents

  1. Executive Summary
  2. Architecture
  3. Requirements
  4. Configuration Mastery
  5. Security Analysis
  6. Operations
  7. Developer Internals
  8. Code Quality & Patterns
  9. Potential Improvements
  10. Troubleshooting
  11. Quick Reference

1. Executive Summary

Attribute Value
Project OpenManus
Version 0.1.0
Language Python (≥ 3.12; runtime warns outside 3.11–3.13)
Paradigm ReAct agent loop + tool-calling, async (asyncio)
Core dependencies openai, pydantic v2, tiktoken, tenacity, mcp, browser-use, playwright, crawl4ai, fastapi/uvicorn, boto3, loguru
LLM backends OpenAI-compatible (default), Azure OpenAI, AWS Bedrock, plus Ollama/Gemini/aggregators via OpenAI-compat
Persistence None (in-memory message history per run)
Auth None
Network services Optional: MCP server (stdio/SSE), A2A server (HTTP :10000)
License MIT

What it is. A framework whose value is the orchestration pattern: how an agent reasons, picks tools, executes them, observes results, and iterates. It is not a CLI utility or a web service — the six entry-point scripts are thin launchers around different agent/flow configurations.

Deployment shape. Single process, run from a terminal or wrapped in a service. All tool execution happens in-process on the host by default; isolation is opt-in (Docker sandbox or Daytona cloud sandbox).


2. Architecture

2.1 The mental model: agent class hierarchy

The single most important thing to understand is the agent inheritance chain. Everything else (tools, flows, prompts) hangs off it.

BaseAgent (ABC, pydantic BaseModel)
  │  state machine (IDLE/RUNNING/FINISHED/ERROR), Memory, run() loop,
  │  is_stuck()/handle_stuck_state(), max_steps
  │
  └── ReActAgent (ABC)
        │  step() = await think() then (if needed) await act()
        │
        └── ToolCallAgent
              │  think(): call llm.ask_tool() with available_tools.to_params()
              │  act():   execute each tool call, append observations to memory
              │  _handle_special_tool(): terminate handling
              │
              ├── Manus            (main.py)        python_execute, browser_use,
              │                                     str_replace_editor, ask_human,
              │                                     terminate, + MCP tools
              ├── BrowserAgent     (library)        browser_use, terminate
              ├── SWEAgent         (library)        bash, str_replace_editor, terminate
              ├── DataAnalysis     (run_flow)       python_execute, viz_prepare,
              │                                     data_visualization, terminate
              ├── MCPAgent         (run_mcp.py)     tools from a connected MCP server
              └── SandboxManus     (sandbox_main)   ask_human, terminate + Daytona
                                                    sandbox tools (shell/files/browser/vision)

Important

BaseAgent.run() is the engine. It transitions the agent to RUNNING, then loops current_step < max_steps and state != FINISHED, calling step() each iteration, checking is_stuck(), and finally calling SANDBOX_CLIENT.cleanup(). The terminate tool is what sets state to FINISHED and ends the loop early.

2.2 The ReAct loop in detail

run(request)
  └─► loop until FINISHED or max_steps:
        step()  ── ReActAgent ──►
          think()  ── ToolCallAgent ──►
            ├─ append next_step_prompt as a user message
            ├─ llm.ask_tool(messages, system, tools, tool_choice)
            ├─ store assistant message (content + tool_calls)
            └─ return True if there are tool calls / content
          act()  ── ToolCallAgent ──►
            └─ for each tool_call:
                 execute_tool() → available_tools.execute(name, args)
                 append tool result to memory (truncated to max_observe)
  • tool_choice is AUTO for most agents (the model may answer or call tools); BrowserAgent also uses AUTO.
  • max_observe caps how much of each tool result is fed back (e.g. Manus = 10000 chars, DataAnalysis = 15000) to control context growth.
  • Stuck detection: if the last assistant message content repeats ≥ duplicate_threshold (2) times, handle_stuck_state() prepends a "consider new strategies" nudge to the next-step prompt.
  • Token-limit handling: a TokenLimitExceeded surfaced through a tenacity RetryError ends the run gracefully (sets FINISHED) rather than crashing.

2.3 Component inventory

Layer Module(s) Responsibility
Entry points main.py, run_flow.py, run_mcp.py, run_mcp_server.py, sandbox_main.py, protocol/a2a/app/main.py Launch a specific agent/flow/server.
Agents app/agent/*.py The ReAct hierarchy above.
LLM client app/llm.py, app/bedrock.py Provider-agnostic ask / ask_tool / ask_with_images; token counting; Bedrock adapter.
Config app/config.py Singleton Config loading config/config.toml into pydantic settings models.
Schema app/schema.py Message, Memory, Role, ToolChoice, AgentState, ToolCall.
Tools app/tool/*.py The tool implementations + ToolCollection.
Flows app/flow/*.py PlanningFlow + FlowFactory for multi-agent orchestration.
Prompts app/prompt/*.py System & next-step prompts per agent.
MCP app/mcp/server.py, app/tool/mcp.py Serve tools over MCP / consume remote MCP tools.
Sandboxes app/sandbox/*, app/daytona/* Local Docker sandbox client + Daytona cloud sandbox.
Protocols protocol/a2a/* Agent-to-Agent (A2A) server wrapping Manus.

2.4 The LLM client (app/llm.py)

LLM is an instance-cached class (_instances keyed by config name, so LLM("default") and LLM("vision") are distinct singletons). It exposes three async methods, all wrapped with tenacity retry (stop_after_attempt(6), exponential backoff):

Method Use
ask() Plain completion (optionally streaming).
ask_tool() Tool/function-calling completion — the agent workhorse. Always non-streaming.
ask_with_images() Multimodal completion with image attachments.

Provider routing (in __init__): api_type == "azure" → AsyncAzureOpenAI; api_type == "aws" → BedrockClient (custom OpenAI-shape adapter over boto3 bedrock-runtime); everything else → AsyncOpenAI(base_url=...). This is why Ollama, Gemini, Jiekou, PPIO, DeepSeek, etc. all work — they expose OpenAI-compatible endpoints.

Token accounting (TokenCounter): counts text via tiktoken (falls back to cl100k_base for unknown models) and estimates image tokens by OpenAI's tiling rules. max_input_tokens, if set, caps cumulative input and raises TokenLimitExceeded.

Note

MULTIMODAL_MODELS and REASONING_MODELS are hard-coded allowlists in app/llm.py. A new vision or reasoning model not in those lists won't get image support / max_completion_tokens handling until added. This is a maintenance point — see §9.

2.5 The tool system

All tools subclass BaseTool (ABC + pydantic BaseModel) with name, description, parameters (a JSON Schema), and an async execute(). to_param() renders the OpenAI function-calling spec. ToolResult (with output / error / base64_image / system) is the uniform return type; CLIResult and ToolFailure are subtypes.

ToolCollection holds tools, maps them by name, renders to_params() for the LLM, and dispatches execute(name, tool_input). Agents add/remove tools dynamically (notably MCP tools).

2.6 Planning flow (app/flow/planning.py)

PlanningFlow (created via FlowFactory.create_flow(FlowType.PLANNING, agents)) is the multi-agent orchestrator behind run_flow.py:

  1. _create_initial_plan() asks the LLM (with the PlanningTool) to draft a titled, numbered plan. If the LLM doesn't call the tool, a default 3-step plan is created.
  2. The execute loop repeatedly finds the first non-completed step, marks it in_progress, picks an executor agent (by [TYPE] tag in the step text, else the first executor / primary agent), and runs it with a step-scoped prompt.
  3. Steps are marked completed; the loop ends when no active step remains or an agent reaches FINISHED.
  4. _finalize_plan() asks the LLM for a summary.

Step status markers: [ ] not started, [→] in progress, [✓] completed, [!] blocked. The only registered FlowType is PLANNING.

2.7 MCP integration

  • As a client (app/tool/mcp.py): MCPClients (a ToolCollection) connects via connect_sse(url) or connect_stdio(command, args), lists server tools, and wraps each as an MCPClientTool named mcp_{server_id}_{tool} (sanitized, ≤ 64 chars). MCPAgent refreshes tools every 5 steps and ends when the server's tool map empties.
  • As a server (app/mcp/server.py): MCPServer wraps FastMCP, registering bash, browser (browser_use), editor (str_replace_editor), and terminate as MCP tools with reconstructed signatures/docstrings.

2.8 Sandboxes

  • Local Docker (app/sandbox/core/*): DockerSandbox + SandboxManager + AsyncDockerizedTerminal provide containerized command/file execution, gated by [sandbox] use_sandbox. LocalSandboxClient (SANDBOX_CLIENT) is the singleton used by file operators.
  • Daytona cloud (app/daytona/*): SandboxManus creates a remote Daytona sandbox, surfaces VNC + website preview URLs, and adds sandbox-scoped tools (SandboxBrowserTool, SandboxFilesTool, SandboxShellTool, SandboxVisionTool).

3. Requirements

Component Requirement
Python ≥ 3.12 (per setup.py); 3.11–3.13 tolerated at runtime
LLM API An OpenAI-compatible endpoint + key, or Azure/Bedrock credentials
Memory/CPU Modest for the framework itself; the browser (Playwright/Chromium) and crawl4ai dominate footprint
Node.js ≥ 18 — only for the chart-visualization toolchain
Docker Only if [sandbox] use_sandbox = true
Daytona API key only for sandbox_main.py
Playwright playwright install to download Chromium for browser automation

Python dependencies (from requirements.txt)

Core: pydantic~=2.10.6, openai~=1.66.3, tenacity~=9.0.0, pyyaml~=6.0.2, loguru~=0.7.3, numpy, tiktoken~=0.9.0, pydantic_core~=2.27.2. LLM/cloud: boto3~=1.37.18 (Bedrock), mcp~=1.5.0, httpx>=0.27.0, tomli>=2.0.0. Web/automation: browser-use~=0.1.40, playwright~=1.51.0, crawl4ai~=0.6.3, beautifulsoup4~=4.13.3, requests~=2.32.3, html2text~=2024.2.26, googlesearch-python, baidusearch, duckduckgo_search~=7.5.3, browsergym~=0.13.3. Serving/data: fastapi~=0.115.11, uvicorn~=0.34.0, datasets~=3.4.1, aiofiles~=24.1.0, pillow~=11.1.0, unidiff~=0.7.5, huggingface-hub~=0.29.2.

Warning

requirements.txt (the source of truth) and setup.py's install_requires disagree. setup.py omits tiktoken, mcp, fastapi, boto3, playwright, crawl4ai, and more, and pins different version ranges (e.g. openai>=1.58.1,<1.67.0). Install from requirements.txt. The setup.py list should be treated as stale.


4. Configuration Mastery

Configuration is loaded once by the Config singleton (app/config.py) at import time from config/config.toml, falling back to config/config.example.toml if the former is absent (FileNotFoundError if neither exists). MCP server entries load separately from config/mcp.json.

4.1 [llm] and named LLM profiles (LLMSettings)

Key Type Default Notes
model str required Model name.
base_url str required API endpoint.
api_key str required Key (unused for Bedrock but still required).
max_tokens int 4096 Per-response cap.
max_input_tokens int? None Cumulative input cap; None = unlimited.
temperature float 1.0 Set 0.0 for agents.
api_type str "" azure / aws route to special clients; all else → OpenAI-compatible.
api_version str "" Azure only.

The loader builds a "default" profile from the top-level [llm] keys, then merges any nested tables (e.g. [llm.vision]) as additional named profiles on top of the defaults. Agents request a profile by name; BaseAgent.initialize_agent() falls back to LLM(config_name=self.name.lower()).

Tip

Per-role / per-purpose models are a first-class feature: define [llm.vision], [llm.<custom>], etc., and different parts of the system use different models in one run. This is the "killer recipe" — e.g. a cheap fast model for reasoning and a vision model only for screenshots.

4.2 [browser] (BrowserSettings)

Key Default Notes
headless false A visible browser opens by default.
disable_security true Browser security relaxed by default.
extra_chromium_args [] Extra Chromium flags.
chrome_instance_path None Attach to an existing Chrome.
wss_url None Connect via WebSocket.
cdp_url None Connect via Chrome DevTools Protocol.
max_content_length 2000 Cap on extracted page content.
[browser.proxy] — server, username, password.

4.3 [search] (SearchSettings)

Key Default
engine Google
fallback_engines ["DuckDuckGo", "Baidu", "Bing"]
retry_delay 60 (s)
max_retries 3
lang en
country us

4.4 [sandbox] (SandboxSettings)

Key Default
use_sandbox false
image python:3.12-slim
work_dir /workspace
memory_limit 512m (example file uses 1g)
cpu_limit 1.0 (example uses 2.0)
timeout 300 (s)
network_enabled false (example uses true)

4.5 [daytona] (DaytonaSettings)

Key Default
daytona_api_key required for sandbox_main
daytona_server_url https://app.daytona.io/api
daytona_target us (eu/us)
sandbox_image_name whitezxj/sandbox:0.1.0
sandbox_entrypoint supervisord command
VNC_password 123456

4.6 [mcp] (MCPSettings) and config/mcp.json

server_reference defaults to app.mcp.server. Server connections come from config/mcp.json (MCPServerConfig: type = sse/stdio, url, command, args).

4.7 [runflow] (RunflowSettings)

use_data_analysis_agent (default false) — when true, run_flow.py adds the DataAnalysis agent alongside Manus.

Note

PROJECT_ROOT is computed from app/config.py's location, and WORKSPACE_ROOT = PROJECT_ROOT/workspace. The agent's working/scratch area and chart outputs live there.


5. Security Analysis

Caution

OpenManus executes arbitrary code and shell commands on the host by default. This is inherent to what an autonomous agent does, but it makes the security posture the most important operational topic. Treat any OpenManus deployment as equivalent to handing an LLM a shell on the machine.

5.1 Arbitrary code & command execution (HIGH)

Several default-equipped tools execute attacker-influenceable (LLM-generated, prompt-influenced) code:

Tool Mechanism Isolation by default
python_execute exec(code, safe_globals, safe_globals) inside a multiprocessing.Process None. safe_globals includes the full __builtins__ — open, os, subprocess import, network, filesystem all available. Only a timeout (default 5 s) bounds it.
bash Spawns /bin/bash via asyncio.create_subprocess_shell None. Full shell on the host.
str_replace_editor Reads/writes/creates arbitrary absolute paths Local filesystem unless sandbox enabled.
computer_use Drives a real desktop (mouse/keyboard/screenshots) Used with sandbox; full GUI control.

Manus (the default agent in main.py) ships python_execute; SWEAgent ships bash; the MCP server exposes bash. The "sandbox" name on PythonExecute refers only to the timeout/subprocess wrapper — it is not a security sandbox.

Mitigations:

  • [ ] Enable the Docker sandbox: [sandbox] use_sandbox = true (routes file ops and shell through a container with CPU/memory/network/timeout limits).
  • [ ] Or use sandbox_main.py (Daytona) so all execution happens in an isolated cloud sandbox.
  • [ ] Run the whole process as an unprivileged user, inside a rootless container, with an egress allowlist and dropped capabilities.
  • [ ] Restrict each agent's tool list in code (agent.available_tools) to remove bash/python_execute for untrusted-input scenarios.
  • [ ] Never expose the MCP server (which registers bash) on an untrusted network.

5.2 Browser exposure (MEDIUM)

Defaults are headless = false and disable_security = true. A visible, security-relaxed browser is driven by the agent and can be steered to arbitrary URLs (including via web_search → auto-open first result). Prompt injection from a visited page can influence the agent. Set headless = true, keep disable_security = false where possible, and treat visited content as untrusted input.

5.3 Secrets handling (MEDIUM)

API keys live in plaintext in config/config.toml. There is no secrets manager and no .env integration in the core (the A2A entry point does call load_dotenv()). Keep config/config.toml out of version control (the repo's config/.gitignore covers this), restrict file permissions, and inject keys via mounted secrets in containerized deployments.

5.4 Network services (MEDIUM)

  • A2A server (:10000) and MCP SSE endpoints have no authentication. Bind to localhost or place behind an authenticating reverse proxy; never expose directly to the internet.
  • The MCP server exposing bash to any connecting client is a remote-code-execution vector if reachable.

5.5 Prompt injection & loop safety (MEDIUM)

The agent ingests web pages, files, and tool outputs into its context; malicious content can attempt to redirect behavior. Built-in is_stuck() mitigates loops but not adversarial steering. The max_steps cap (20) and run_flow.py's 60-minute timeout bound runaway execution.

5.6 OWASP Agentic-AI mapping (summary)

Threat Relevance Default state
Tool misuse / RCE python_execute, bash Not mitigated by default; sandbox is opt-in
Excessive agency autonomous multi-tool loop Bounded by max_steps, terminate
Prompt injection web/file content in context Not mitigated; user must trust sources
Insecure output handling tool results fed back verbatim Truncated via max_observe only
Unauthenticated services A2A / MCP Not authenticated; deploy behind proxy

6. Operations

6.1 Running as a service

There is no daemon mode for the agent scripts (they are interactive or single-prompt). For service use, wrap main.py --prompt ... or the A2A server in a process manager (systemd, supervisor, a container CMD). The A2A server runs under uvicorn:

python protocol/a2a/app/main.py --host 0.0.0.0 --port 10000

Warning

Binding --host 0.0.0.0 exposes an unauthenticated agent endpoint. Only do this behind a trusted network boundary or an authenticating proxy.

6.2 Logging

Logging uses loguru (app/logger.py). On each run, define_log_level() adds a stderr sink at INFO and a file sink at DEBUG under logs/{timestamp}.log.

Caution

A new timestamped log file is created per run (GitHub issue #1008 — "Wrong creation of a large number of log files"). Without rotation, logs/ grows unbounded. Add a cron/cleanup job or a loguru rotation/retention policy.

6.3 Token & cost control

  • Set [llm] max_input_tokens to cap cumulative input and force a graceful stop via TokenLimitExceeded.
  • Tune max_tokens and choose cheaper models for simple agents.
  • The LLM client logs cumulative input/completion tokens at INFO after each call — scrape these for cost monitoring.

6.4 Resource cleanup

BaseAgent.run() calls SANDBOX_CLIENT.cleanup() at the end. ToolCallAgent.cleanup() calls each tool's async cleanup() (closing browser contexts, MCP sessions, aiohttp sessions). SandboxManus.cleanup() also deletes the Daytona sandbox. Always let the process shut down cleanly (Ctrl+C is handled) so the browser and sandboxes are released.

6.5 Backups / state

There is no persistent state to back up — message memory is in-process and discarded at exit. The only durable artifacts are files the agent writes (working directory, workspace/, logs/).


7. Developer Internals

7.1 Repository structure

OpenManus/
├── main.py run_flow.py run_mcp.py run_mcp_server.py sandbox_main.py
├── setup.py requirements.txt Dockerfile
├── app/
│   ├── agent/        base, react, toolcall, manus, browser, swe, mcp,
│   │                 data_analysis, sandbox_agent
│   ├── tool/         base, bash, browser_use_tool, python_execute,
│   │                 str_replace_editor, web_search, crawl4ai, planning,
│   │                 terminate, ask_human, create_chat_completion,
│   │                 computer_use, file_operators, mcp, tool_collection,
│   │                 search/ (google,baidu,bing,duckduckgo), sandbox/,
│   │                 chart_visualization/
│   ├── flow/         base, flow_factory, planning
│   ├── prompt/       manus, browser, swe, mcp, planning, toolcall, visualization
│   ├── mcp/          server
│   ├── sandbox/      client, core/(sandbox, manager, terminal, exceptions)
│   ├── daytona/      sandbox, tool_base
│   ├── llm.py bedrock.py config.py schema.py logger.py exceptions.py
├── config/           config.example*.toml, mcp.example.json
├── protocol/a2a/     A2A server (agent, agent_executor, main)
├── examples/         benchmarks, use cases
├── tests/sandbox/    sandbox test suite
└── workspace/        agent scratch / outputs

7.2 Key abstractions

Abstraction Defined in Contract
BaseAgent app/agent/base.py run() loop, state_context(), update_memory(), abstract step().
ReActAgent app/agent/react.py abstract think() + act(); step() = think→act.
ToolCallAgent app/agent/toolcall.py concrete tool-calling think/act; special-tool handling.
BaseTool app/tool/base.py name/description/parameters + async execute() + to_param().
ToolCollection app/tool/tool_collection.py tool registry + dispatch.
Message/Memory app/schema.py OpenAI-shaped messages; bounded history (max_messages=100).
LLM app/llm.py provider-agnostic ask/ask_tool/ask_with_images.
BaseFlow/PlanningFlow app/flow/* multi-agent orchestration.
FileOperator app/tool/file_operators.py LocalFileOperator vs SandboxFileOperator strategy.

7.3 Extending OpenManus

Add a tool:

from app.tool.base import BaseTool, ToolResult

class MyTool(BaseTool):
    name: str = "my_tool"
    description: str = "What it does (the model reads this to decide to call it)."
    parameters: dict = {
        "type": "object",
        "properties": {"arg": {"type": "string", "description": "..."}},
        "required": ["arg"],
    }

    async def execute(self, arg: str) -> ToolResult:
        return ToolResult(output=f"did something with {arg}")

Then add it to an agent's available_tools (a ToolCollection).

Add an agent: subclass ToolCallAgent, set name, description, system_prompt, next_step_prompt, available_tools, and (optionally) override think().

Add a flow: subclass BaseFlow, implement execute(), and register it in FlowFactory.flows under a new FlowType.

Add an LLM provider: if it's OpenAI-compatible, just set base_url. Otherwise add a branch in LLM.__init__ (as aws/azure do) and an adapter like app/bedrock.py.

7.4 Testing

The test suite under tests/sandbox/ (test_client.py, test_sandbox.py, test_sandbox_manager.py, test_docker_terminal.py) covers the Docker sandbox layer and requires Docker. Run with pytest:

pytest tests/sandbox -q

Note

Test coverage is concentrated on the sandbox subsystem. The agent loop, tool implementations, LLM client, and flows have no dedicated unit tests in-repo — a notable gap (see §9).


8. Code Quality & Patterns

Strengths.

  • Clean layered inheritance (BaseAgent → ReActAgent → ToolCallAgent) makes new agents cheap.
  • Strategy pattern for file operations (LocalFileOperator/SandboxFileOperator) cleanly toggles local vs sandbox.
  • Provider-agnostic LLM client with a uniform ToolResult keeps tool code simple.
  • Pydantic v2 settings models give validated, self-documenting config.
  • Consistent async throughout; graceful resource cleanup; tenacity retries on API calls.
  • Pre-commit hooks (black, autoflake, isort, standard hygiene hooks) are configured.

Weaknesses / risks.

  • setup.py dependency list is stale and inconsistent with requirements.txt (missing tiktoken etc.).
  • Hard-coded model allowlists (MULTIMODAL_MODELS, REASONING_MODELS) require code edits for new models.
  • app/bedrock.py uses a module-global CURRENT_TOOLUSE_ID (commented "Tmp solution") — not concurrency-safe across simultaneous Bedrock tool calls.
  • Bug in web_search.py (WebContentFetcher.fetch_content): the HTTP header is keyed "WebSearch" instead of "User-Agent" (GitHub issue #1334), so the intended browser UA is never sent.
  • Broad retry_if_exception_type((OpenAIError, Exception, ValueError)) retries everything, masking some non-transient failures.
  • No unit tests outside the sandbox subsystem.
  • Code mixes English and Chinese comments/docstrings (e.g. __add__ docstrings, sandbox-agent comments).

9. Potential Improvements

  • [ ] Reconcile setup.py with requirements.txt — add tiktoken, mcp, fastapi, boto3, playwright, crawl4ai, etc., or have setup.py read from requirements.txt. Eliminates the #1019 tiktoken failure.
  • [ ] Fix the web_search UA header bug (#1334): change {"WebSearch": ...} to {"User-Agent": ...} in WebContentFetcher.fetch_content.
  • [ ] Make python_execute genuinely sandboxed by default, or rename it so its lack of isolation isn't implied to be safe. Restrict __builtins__, or always route through the Docker/Daytona sandbox.
  • [ ] Externalize model capability lists (MULTIMODAL_MODELS, REASONING_MODELS) to config so new models don't need code changes.
  • [ ] Add log rotation/retention (#1008) to stop unbounded logs/ growth.
  • [ ] Make CURRENT_TOOLUSE_ID instance-scoped in app/bedrock.py for concurrency safety.
  • [ ] Authenticate the A2A and MCP-SSE endpoints, or document a required reverse-proxy auth layer.
  • [ ] Add unit tests for the agent loop, tool execution, and the LLM client (currently only the sandbox is covered).
  • [ ] Loosen or validate pinned deps (#1360 crawl4ai/pillow conflict) and document a known-good lockfile.
  • [ ] Tighten retry predicates so non-transient errors aren't retried six times.

10. Troubleshooting

Error: ModuleNotFoundError: No module named 'tiktoken'

Installed via setup.py. Run pip install -r requirements.txt (or pip install tiktoken). Root cause: setup.py omits the dependency (#1019).

Error: No configuration file found in config directory

Neither config/config.toml nor config/config.example.toml exists. Restore the example file and copy it: cp config/config.example.toml config/config.toml.

Error: Docker Initialization failing / sandbox tools fail

Docker isn't running, or the [sandbox] image can't be pulled. Start Docker, verify docker ps, pull python:3.12-slim, or set use_sandbox = false. The sandbox raises RuntimeError: Sandbox not initialized when used without a live container.

Error: password must be provided (sandbox_main.py)

Daytona key/VNC password missing. Set [daytona] daytona_api_key (and VNC_password if needed), or use a non-sandbox entry point.

Error: Server URL is required for SSE connection / Command is required for stdio connection

MCP connection args are incomplete. For SSE pass --server-url; for stdio ensure a command is configured.

Error: Invalid 'tools[1].function.description': string too long (HTTP 500)

A tool description (often a verbose MCP tool) exceeds the provider's limit (#993). Shorten tool descriptions or disconnect the offending MCP server.

Error: Tool calls required but none provided

A REQUIRED tool-choice agent got plain text. Use a strong function-calling model; keep temperature = 0.0.

Error: TokenLimitExceeded / "Maximum token limit reached"

Cumulative input exceeded max_input_tokens. Raise the cap, shorten the task, or use a larger-context model. The agent ends gracefully rather than crashing.

Error: No replacement was performed, old_str ... did not appear verbatim

str_replace_editor requires an exact, unique match. Provide more surrounding context so old_str is unique, mind whitespace, or use view first.

Error: web search yields nothing

All engines failed (All search engines failed... Giving up.). Change [search] engine, raise max_retries, check network/proxy. Note the User-Agent header bug (#1334) can break full-content fetching even when search itself succeeds.

Error: Gemini 2.0 doesn't work (#1037)

Tool-calling incompatibility on Gemini's OpenAI-compatible endpoint. Prefer a strongly function-calling model; verify the rest of the pipeline with OpenAI/Anthropic.

Reference: canonical error sources

app/exceptions.py defines ToolError, OpenManusError, and TokenLimitExceeded. Tool-level ToolError messages (from planning, str_replace_editor, bash) are the most user-facing and are surfaced verbatim in tool observations.


11. Quick Reference

Entry points → agent/flow

Script Agent / flow Notable args
main.py Manus --prompt
run_flow.py PlanningFlow over Manus (+DataAnalysis if enabled) (interactive)
run_mcp.py MCPAgent -c/--connection, --server-url, -i/--interactive, -p/--prompt
run_mcp_server.py / app/mcp/server.py MCPServer (FastMCP) --transport stdio
sandbox_main.py SandboxManus (Daytona) --prompt
protocol/a2a/app/main.py A2A server wrapping A2AManus --host, --port (10000)

Agent defaults

Agent max_steps max_observe Tools
ToolCallAgent (base) 30 — create_chat_completion, terminate
Manus 20 10000 python_execute, browser_use, str_replace_editor, ask_human, terminate, +MCP
BrowserAgent 20 10000 browser_use, terminate
SWEAgent 20 — bash, str_replace_editor, terminate
DataAnalysis 20 15000 python_execute, viz_prepare, data_visualization, terminate
MCPAgent 20 — remote MCP tools (refresh every 5 steps)
SandboxManus 20 10000 ask_human, terminate + Daytona sandbox tools

Agent states

IDLE → RUNNING → (FINISHED on terminate/done, or ERROR on exception, reverted via state_context).

Plan step markers

[ ] not_started · [→] in_progress · [✓] completed · [!] blocked

Default ports / limits

Item Value
A2A server :10000
MCP SSE default http://127.0.0.1:8000/sse
Planning-flow timeout 3600 s
Default max_steps 20
Bash command timeout 120 s
python_execute timeout 5 s
Sandbox command timeout 300 s
Memory max_messages 100
LLM retry attempts 6 (exponential backoff)