How State Is Passed Between the Architect and Developer Agents Using AgentState in swe-agent
State flows from the Architect to the Developer through a shared Pydantic implementation_plan field, where an orchestrator invokes the Architect workflow first, extracts the final state, and initializes the Developer workflow with that same structured data.
The swe-agent repository implements a multi-agent software engineering pipeline where distinct Architect and Developer agents collaborate to solve coding tasks. Understanding exactly how state is passed between the Architect and Developer agents using AgentState is essential for tracing data flow in this LangGraph-based system. Both agents maintain their own Pydantic BaseModel state classes—SoftwareArchitectState and SoftwareDeveloperState—that expose a common implementation_plan field to enable type-safe hand-offs without external storage or manual serialization.
Agent-Specific State Models
Each agent defines its own state schema in dedicated files, yet both rely on the same shared entities to ensure compatibility during transitions.
Architect State Definition
The Architect agent operates on the SoftwareArchitectState class defined in agent/architect/state.py. This model tracks research activities and, crucially, holds the implementation_plan that will be handed off:
class SoftwareArchitectState(BaseModel):
research_next_step: Optional[str] = Field(None, description="...")
implementation_plan: Optional[ImplementationPlan] = Field(None, description="The implementation plan to be executed")
implementation_research_scratchpad: Annotated[list[AnyMessage], add_messages] = Field([], description="Scratchpad for research")
is_valid_research_step: Optional[bool] = Field(None, description="Whether the research step is valid")
Developer State Definition
The Developer agent uses SoftwareDeveloperState from agent/developer/state.py, which includes progress tracking fields plus the same implementation_plan field to receive the Architect's output:
class SoftwareDeveloperState(BaseModel):
implementation_plan: Optional[ImplementationPlan] = Field(None, description="The implementation plan to be executed")
current_task_idx: Optional[int] = Field(0, description="The current task index")
current_atomic_task_idx: Optional[int] = Field(0, description="The current atomic task")
atomic_implementation_research: Annotated[list[AnyMessage], add_messages_with_clear]
codebase_structure: Optional[str] = Field(None, description="Code-base tree")
current_file_content: Optional[str] = Field(None, description="File content being edited")
How the Architect Populates the Shared State
The Architect workflow concludes with the extract_implementation_plan node located in agent/architect/graph.py. This node processes research findings, queries the codebase structure, and constructs a structured ImplementationPlan object:
def extract_implementation_plan(state: SoftwareArchitectState):
response = extract_implementation_runnable.invoke({
"research_findings": convert_tools_messages_to_ai_and_human(state.implementation_research_scratchpad),
"codebase_structure": get_files_structure.invoke({"directory": "./workspace_repo"}),
"output_format": JsonOutputParser(pydantic_object=ImplementationPlan).get_format_instructions()
})
response = ImplementationPlan(**response) # Concrete Pydantic object
return {"implementation_plan": response}
Because the workflow is built with StateGraph(SoftwareArchitectState), returning {"implementation_plan": response} automatically updates the implementation_plan field on the state instance.
The State Hand-Off to the Developer
The transition between agents occurs at the orchestration layer. The orchestrator retrieves the final state from the Architect workflow and uses it to initialize the Developer workflow. Since both state models expose the identically named implementation_plan field, LangGraph's built-in state merging handles the transfer automatically:
# Run the architect workflow and obtain its final state
arch_result = swe_architect.invoke({"implementation_research_scratchpad": []})
plan = arch_result["implementation_plan"]
# Feed that plan into the developer workflow
dev_result = swe_developer.invoke({
"implementation_plan": plan,
"atomic_implementation_research": [] # Start with clean scratchpad
})
The implementation_plan value from SoftwareArchitectState becomes the initial value for SoftwareDeveloperState without transformation or external persistence.
How the Developer Consumes AgentState
Inside agent/developer/graph.py, the Developer reads the shared plan to drive execution. The get_clear_implementation_plan_for_atomic_task node accesses the current task and atomic task indices to determine what to implement next:
def get_clear_implementation_plan_for_atomic_task(state: SoftwareDeveloperState):
current_task = state.implementation_plan.tasks[state.current_task_idx]
current_atomic_task = current_task.atomic_tasks[state.current_atomic_task_idx]
# Invoke LLM prompt to clarify implementation details...
return {"atomic_implementation_research": [result]}
All subsequent nodes—including creating_diffs_for_task and proceed_to_next_atomic_task—read from state.implementation_plan to understand the target files and required changes. The Developer updates its own progress counters (current_task_idx, current_atomic_task_idx) within its state while treating the plan as immutable input data.
Summary
- AgentState is implemented as Pydantic
BaseModelclasses—SoftwareArchitectStateandSoftwareDeveloperState—that enable automatic serialization by LangGraph. - The
implementation_planfield serves as the canonical data structure shared between agents, defined inagent/common/entities.py. - The Architect's
extract_implementation_plannode inagent/architect/graph.pypopulates the plan by parsing research findings and codebase structure. - An external orchestrator passes the Architect's final state directly into the Developer's initial invocation, leveraging LangGraph's automatic state merging.
- The Developer reads the plan in
agent/developer/graph.pyto iterate through tasks and atomic subtasks while maintaining independent progress tracking fields.
Frequently Asked Questions
What is the shared data structure between Architect and Developer states?
The ImplementationPlan class, referenced in both SoftwareArchitectState and SoftwareDeveloperState, serves as the shared data structure. It contains a list of tasks with atomic subtasks, target file paths, and implementation details. This class is defined in agent/common/entities.py and ensures type compatibility during the hand-off.
How does LangGraph handle the state transition between agents?
LangGraph automatically merges dictionary inputs with the target workflow's Pydantic state model. When the orchestrator invokes the Developer workflow with {"implementation_plan": plan}, the framework matches the dictionary key to the implementation_plan field on SoftwareDeveloperState and instantiates the model accordingly, eliminating manual mapping or serialization code.
Can the Developer modify the implementation plan received from the Architect?
While the Developer technically could modify the implementation_plan object, the swe-agent implementation treats it as read-only configuration. The Developer updates its own state fields—such as current_task_idx and atomic_implementation_research—to track progress, but it does not write changes back to the plan itself, preserving the Architect's original design intent.
Where is the ImplementationPlan class defined?
The ImplementationPlan class is defined in agent/common/entities.py. This central location allows both the Architect and Developer agents to import and reference the same schema, ensuring that the data structure remains consistent across the state boundary and preventing drift between the planning and implementation phases.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →