# Managing Incremental Development Cycles and State Updates in MetaGPT

> Master incremental development cycles and state updates in MetaGPT. Learn how the --inc flag and rc.state mechanism enable seamless AI agent resumption and persistent action sequences for efficient software development.

- Repository: [FoundationAgents/MetaGPT](https://github.com/FoundationAgents/MetaGPT)
- Tags: best-practices
- Published: 2026-03-04

---

**MetaGPT enables incremental software development through the `--inc` CLI flag for loading existing repositories and the `rc.state` mechanism in `BaseRole` that persists action sequences across interruptions, allowing AI agents to resume development from exact breakpoints.**

MetaGPT is an extensible Python framework where autonomous AI agents called **Roles** collaborate to design, develop, and refine software projects. Managing incremental development cycles and state updates in MetaGPT relies on two core mechanisms: the incremental mode flag that loads existing codebases without restarting from scratch, and the role state machine that tracks execution progress through indexed action sequences. Together, these systems allow a single CLI command to load legacy code, create a fresh AI-driven development loop, and resume from the exact point where the previous run terminated.

## Understanding MetaGPT's Incremental Development Architecture

### The Incremental Mode Flag (`--inc`)

The `--inc` flag triggers MetaGPT's incremental development capability, allowing the framework to work on an existing repository rather than generating a new project from scratch. When activated, the system parses the existing codebase, creates a Git tag named `base` to preserve the original state, and injects the project path into the configuration context.

This mechanism is implemented in [`metagpt/software_company.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/software_company.py) within the `generate_repo` function, which handles the CLI argument parsing and delegates to `config.update_via_cli` to set the incremental flag and project path.

### Role State Machines and `rc.state`

Each Role in MetaGPT maintains an internal state machine through the `RoleContext` object (`self.rc`). The critical field `rc.state` stores an integer index pointing to the current action in the role's `self.actions` list. This state persists across interruptions and enables precise recovery.

The state management logic resides in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py), where the `_set_state` method updates `rc.state` and synchronizes the next todo action:

```python
def _set_state(self, state: int):
    """Update the current state."""
    self.rc.state = state
    logger.debug(f"actions={self.actions}, state={state}")
    self.set_todo(self.actions[self.rc.state] if state >= 0 else None)

```

## How MetaGPT Implements Incremental Development Cycles

### Configuration and CLI Entry Points

MetaGPT's configuration system in [`metagpt/config2.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/config2.py) uses a Pydantic-based `Config` model to merge environment variables, YAML files, and CLI arguments. When the `--inc` flag is present, the `update_via_cli` method marks the run as incremental and records the existing repository path:

```python

# metagpt/software_company.py

def generate_repo(..., inc=False, project_path="", ...):
    # …

    config.update_via_cli(project_path, project_name, inc, reqa_file, max_auto_summarize_code)
    ctx = Context(config=config)
    # …

```

This configuration then propagates through the `Context` object to all roles and actions.

### Team Assembly and Round-Based Execution

The `generate_repo` function constructs a `Team` object (defined in [`metagpt/team.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/team.py)) and hires the standard pipeline of roles:

```python
company = Team(context=ctx)
company.hire([
    TeamLeader(),
    ProductManager(),
    Architect(),
    Engineer2(),
    DataAnalyst(),
])

```

The `Team.run()` method initiates a round-based loop where each role executes its `_think` and `_act` methods. During incremental runs, roles read the existing repository state from disk before proposing modifications, ensuring continuity with the legacy codebase.

### Git Tag Management for Base State Preservation

Before AI agents modify files, MetaGPT creates a Git tag named `base` to preserve the original repository state. This functionality, implemented in [`metagpt/utils/git_repository.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/utils/git_repository.py), allows the system to:

1. Compare changes between the original and modified states
2. Rollback to the base state if necessary
3. Generate diffs for review purposes

The test harness in [`tests/metagpt/test_incremental_dev.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/tests/metagpt/test_incremental_dev.py) demonstrates this workflow through the `check_or_create_base_tag` helper function, which prepares archived projects for incremental development testing.

## State Update Mechanisms in MetaGPT Roles

### The `_set_state` Method and State Transitions

State transitions in MetaGPT roles follow a deterministic pattern governed by the `_think` method. When `react_mode` is set to `"by_order"`, the role simply increments `rc.state` to proceed to the next action. For more complex workflows, the role prompts the LLM to select the next state number based on current context.

The `_set_state` method in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py) (lines 302-313) performs three critical operations:

1. Updates the integer index in `self.rc.state`
2. Logs the available actions and new state for debugging
3. Sets the current todo action by indexing into `self.actions`

### Persistence and Recovery with Binary Serialization

MetaGPT implements robust persistence through binary serialization of the entire `Team` state. The `Team.serialize()` method creates a `.team` file containing:

- All role contexts (`rc` objects)
- Action histories
- Message buffers
- Git repository state

Recovery is handled by `Team.deserialize()` in [`metagpt/team.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/team.py):

```python
if recover_path:
    stg_path = Path(recover_path)
    company = Team.deserialize(stg_path=stg_path, context=ctx)
    idea = company.idea

```

Because `rc.state` is part of the serialized `RoleContext`, the framework resumes execution from the exact breakpoint, maintaining continuity across system restarts or crashes.

## Practical Examples: Running Incremental Development

### Running an Incremental Development Session

To evolve an existing codebase with new requirements, use the `--inc` flag combined with `--project-path`:

```bash

# 1️⃣  Prepare an existing repo (e.g. cloned at ./old_project)

# 2️⃣  Issue a new requirement to MetaGPT

metagpt startup \
    "Add a dark mode toggle to the UI" \
    --inc \
    --project-path ./old_project \
    --n-round 30 \
    --code-review \
    --investment 5.0

```

**What happens under the hood:**

- The CLI parses `--inc` and sets `Config.inc = True` via `update_via_cli` in [`metagpt/config2.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/config2.py)
- `software_company.generate_repo` loads the old repo, creates a `base` Git tag, and builds a fresh `Team`
- The `Team` runs a multi-round loop; each role updates its `rc.state` and writes commits to the repository

### Inspecting Role State at Runtime

You can programmatically inspect and manipulate role states for debugging or custom workflows:

```python
from metagpt.roles.engineer import Engineer2
from metagpt.context import Context
from metagpt.config2 import config

ctx = Context(config=config)
engineer = Engineer2()
engineer.set_env(ctx.env)          # bind to environment

engineer._set_state(2)            # jump to the 3rd action

print(engineer.rc.state)          # → 2

print(engineer.rc.todo)           # currently scheduled Action object

```

This snippet directly manipulates `rc.state` (via the private `_set_state` method) – the same mechanism the framework uses automatically after each successful action in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py).

### Serializing and Recovering a Team

To persist progress across system restarts:

```python

# Serialize after 10 rounds

team_path = team.serialize()   # creates <project_path>/team/<timestamp>.team

# Later, resume from the saved snapshot

recovered_team = Team.deserialize(stg_path=team_path, context=Context())
await recovered_team.run(n_round=20, idea="Continue development")

```

The restored `Team` brings back each role’s `rc.state`, enabling seamless continuation of incremental development cycles even after hardware failures or planned maintenance.

## Summary

- **Incremental mode** (`--inc`) allows MetaGPT to work on existing repositories by loading legacy code, creating a `base` Git tag for rollback protection, and injecting the project path into the configuration via `software_company.generate_repo`.

- **Role state machines** track execution progress through the `rc.state` integer index in `RoleContext`, which points to the current action in the role's action list and persists across interruptions.

- **State transitions** are managed by the `_set_state` method in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py), which updates the state index and synchronizes the next todo action for deterministic workflow progression.

- **Persistence and recovery** rely on binary serialization of the entire `Team` state to `.team` files, allowing `Team.deserialize` to restore exact role contexts including `rc.state` for seamless continuation of development cycles.

## Frequently Asked Questions

### How does MetaGPT handle existing codebases without overwriting them?

MetaGPT uses the `--inc` (incremental) flag combined with `--project-path` to load existing repositories. The framework creates a `base` Git tag via `check_or_create_base_tag` in [`metagpt/utils/git_repository.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/utils/git_repository.py) to preserve the original state, then applies new requirements through AI-driven development cycles without destroying legacy code.

### What is the `rc.state` variable in MetaGPT roles?

The `rc.state` variable is an integer index stored in the `RoleContext` object (`self.rc`) that tracks which action a role should execute next. Defined in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py), this state is updated via `_set_state` and persists across serialization cycles, enabling roles to resume from exact breakpoints after system interruptions.

### How can I resume a MetaGPT project after a crash?

Use the binary serialization feature by calling `team.serialize()` to create a `.team` snapshot file. To resume, invoke `Team.deserialize(stg_path=team_path, context=Context())` which restores all role contexts including `rc.state` values, then continue execution with `await recovered_team.run()`. This mechanism is implemented in [`metagpt/team.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/team.py).

### What is the difference between `by_order` and LLM-based state selection?

When `react_mode` is set to `"by_order"`, MetaGPT roles increment `rc.state` sequentially through their action list. For complex workflows, the `_think` method prompts the LLM to select the next state number based on current context and observations. Both approaches use `_set_state` in [`metagpt/roles/role.py`](https://github.com/FoundationAgents/MetaGPT/blob/main/metagpt/roles/role.py) to update the role's execution pointer.