How to Customize Standard Operating Procedures (SOP) for Agent Workflows in MetaGPT

To customize SOPs in MetaGPT, toggle the use_fixed_sop flag in RoleZero-based classes to switch between dynamic LLM-driven planning and static, predefined action pipelines.

MetaGPT treats Standard Operating Procedures (SOP) as configurable behavioral rules that govern how each role (agent) reacts to inputs, selects tools, and executes actions. By customizing the SOP configuration in the MetaGPT framework, you can shape deterministic workflows with explicit step-by-step logic or enable adaptive, LLM-generated execution strategies. This guide covers the architectural mechanics, source code references, and practical implementations for both fixed and dynamic SOP modes.

SOP Architecture and the use_fixed_sop Switch

The MetaGPT architecture centers on the RoleZero base class in metagpt/roles/di/role_zero.py, which implements the core SOP logic. Every role inherits from this class and respects the use_fixed_sop boolean flag (default False) stored in the instance.

When use_fixed_sop is False, the role enters dynamic SOP mode. In this mode, the _think() method builds an execution plan, queries the LLM for decisions, and uses the ToolRecommender to suggest relevant tools based on the current task context. This creates an adaptive "think-act" loop where the agent iteratively plans and executes until completion or budget exhaustion.

When use_fixed_sop is True, the role enters fixed SOP mode. The _think() method returns early, bypassing LLM-driven planning entirely. Instead, the role executes a static list of predefined actions set during initialization via set_actions(). This mode also typically disables memory tracking to ensure deterministic execution.

The Team class in metagpt/team.py (lines 34-36) aggregates these roles and stores the overall SOP description in its docstring, serving as the high-level container that orchestrates multi-agent workflows.

Implementing Fixed SOP Workflows

Fixed SOPs provide deterministic, repeatable workflows ideal for structured tasks like requirements gathering or architectural design. To implement a fixed SOP, you must override the role's __init__ method to set use_fixed_sop=True, disable memory, and define a static action pipeline.

Fixed SOP Implementation Pattern

The ProductManager role in metagpt/roles/product_manager.py (lines 43-48) demonstrates the canonical pattern:

def __init__(self, **kwargs):
    super().__init__(**kwargs)
    self.use_fixed_sop = True
    self.enable_memory = False
    self.set_actions([PrepareDocuments, WritePRD])

Key configuration points for fixed SOPs include:

  • use_fixed_sop = True – Forces the role to skip the LLM planning phase in RoleZero._think().
  • enable_memory = False – Disables conversation memory to ensure the role follows the exact script without historical context interference.
  • set_actions([...]) – Accepts a list of action classes or callables that execute sequentially in the order provided.

The Architect role in metagpt/roles/architect.py (lines 46-48) extends this pattern by additionally mapping custom tool execution logic through _update_tool_execution(), allowing specific tool calls like Terminal.run_command within the fixed workflow.

Configuring Dynamic SOP Behavior

Dynamic SOPs leverage the LLM's reasoning capabilities for adaptive problem-solving. When use_fixed_sop remains False (the default), RoleZero._think() executes its full logic:

  1. Builds a plan based on the current task and context.
  2. Queries the ToolRecommender to suggest a subset of available tools relevant to the task.
  3. Generates a command string for the LLM to decide the next action.
  4. _act() parses the command string, executes the selected tool(s), and loops until task completion.

This mode is ideal for complex, exploratory tasks where the solution path cannot be predetermined. The dynamic behavior is implemented in metagpt/roles/di/role_zero.py (lines 19-22) where tools = await self.tool_recommender.recommend_tools() populates the context-aware tool selection.

Practical Customization Examples

Creating a Custom Fixed-SOP Role

The following example creates a DataAnalyst role with a hardcoded analysis pipeline:

from metagpt.roles.di.role_zero import RoleZero
from metagpt.prompts.di.role_zero import ROLE_INSTRUCTION

class DataAnalyst(RoleZero):
    name = "Dana"
    profile = "Data Analyst"
    instruction = ROLE_INSTRUCTION
    tools = ["Editor:write,read", "Browser:search"]

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.use_fixed_sop = True
        self.enable_memory = False
        self.set_actions([self._load_data, self._run_analysis])

    async def _load_data(self):
        return "Data loaded from source."

    async def _run_analysis(self):
        return "Analysis complete."

In this configuration, the tools attribute restricts the available toolbox, preventing the LLM from recommending unrelated utilities even if the role were temporarily switched to dynamic mode. The set_actions() method injects the static pipeline [self._load_data, self._run_analysis].

Switching SOP Modes at Runtime

You can dynamically alter SOP behavior after instantiation by modifying the flag before adding the role to a team:

from metagpt.roles.architect import Architect
from metagpt.team import Team

arch = Architect()
arch.use_fixed_sop = False  # Enable dynamic LLM planning

team = Team()
team.hire([arch])
team.run_project("Design a micro-service architecture")
await team.run()

When use_fixed_sop=False, the Architect will use the tool recommendation engine and iterative planning rather than the fixed action sequence defined in its class.

Integrating with Team Workflows

To deploy a fixed-SOP agent within a multi-agent team:

from metagpt.roles.product_manager import ProductManager
from metagpt.team import Team

pm = ProductManager(use_fixed_sop=True)

team = Team()
team.hire([pm])
team.run_project("Create a PRD for a todo-list app")
await team.run(n_round=3)

The Team.run() coroutine iterates over hired roles, respecting their individual SOP modes, and terminates when all roles are idle or the budget is exhausted.

Key Source Files for SOP Customization

When customizing Standard Operating Procedures, consult these specific files and line ranges:

  • metagpt/roles/di/role_zero.py (lines 98-104) – Contains the use_fixed_sop flag definition and the _think() method logic that branches between fixed and dynamic execution paths.
  • metagpt/roles/product_manager.py (lines 43-48) – Reference implementation of a fixed-SOP role with disabled memory and static actions.
  • metagpt/roles/architect.py (lines 46-48) – Demonstrates fixed-SOP configuration with custom tool execution mapping.
  • metagpt/team.py (lines 34-36) – Defines the Team container and documents the overall SOP concept for multi-agent orchestration.
  • metagpt/strategy/task_type.py (lines 73-75) – Contains the TaskType.DEVELOP_SOFTWARE SOP description used for task-type routing and pipeline selection.

Summary

  • MetaGPT SOPs are controlled by the use_fixed_sop boolean in RoleZero-derived classes, defaulting to dynamic LLM-driven behavior.
  • Fixed SOPs bypass LLM planning by setting use_fixed_sop=True, disabling memory, and using set_actions() to define explicit execution pipelines.
  • Dynamic SOPs leverage RoleZero._think() to generate plans, recommend tools via ToolRecommender, and iteratively refine actions.
  • Source code locations: Core logic resides in metagpt/roles/di/role_zero.py, with implementation examples in metagpt/roles/product_manager.py and metagpt/roles/architect.py.

Frequently Asked Questions

What is the difference between fixed and dynamic SOP in MetaGPT?

Fixed SOP disables LLM-driven planning and executes a predefined list of actions sequentially, making it ideal for deterministic workflows. Dynamic SOP (the default) uses the _think() method to generate plans on-the-fly, recommends tools dynamically, and allows the agent to adapt its strategy based on intermediate results. The mode is controlled by the use_fixed_sop flag in RoleZero.

How do I disable memory when using fixed SOP?

Set self.enable_memory = False in the role's __init__ method, as demonstrated in ProductManager (metagpt/roles/product_manager.py, lines 43-48). This prevents the role from accessing conversation history, ensuring it follows the static action pipeline without context interference.

Can I switch SOP modes after initializing a role?

Yes. The use_fixed_sop attribute is a public instance variable that can be toggled at runtime before the role joins a team workflow. For example, you can instantiate an Architect, then set arch.use_fixed_sop = False to enable dynamic planning for a specific project without modifying the class definition.

Which source file contains the main SOP logic?

The primary SOP logic resides in metagpt/roles/di/role_zero.py, specifically lines 98-104 where the use_fixed_sop flag is defined and checked, and lines 19-22 where the dynamic tool recommendation occurs. This file serves as the base class for all customizable agent roles in MetaGPT.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →