01 — Entry Points & Execution Flow
Entry Points
OpenHands has three main entry points, corresponding to different deployment modes.
1. CLI Entry Point (V0 — Legacy)
File: openhands/core/main.py:361-395
if __name__ == '__main__':
args = parse_arguments()
config: OpenHandsConfig = setup_config_from_args(args)
task_str = read_task(args, config.cli_multiline_input)
initial_user_action = MessageAction(content=task_str)
sid = generate_sid(config, session_name)
asyncio.run(
run_controller(
config=config,
initial_user_action=initial_user_action,
sid=sid,
fake_user_response_fn=None if args.no_auto_continue else auto_continue_response,
)
)The CLI reads a task from -t, -f, or stdin, wraps it as a MessageAction,
and hands it to run_controller() (line 59). In headless mode, the
auto_continue_response function (line 322) automatically tells the agent to
keep going without waiting for user input.
2. Web Server (V0 — Legacy)
File: openhands/server/__main__.py:16-34
def main():
uvicorn.run(
'openhands.server.listen:app',
host='0.0.0.0',
port=int(os.environ.get('port') or '3000'),
)Starts a Uvicorn ASGI server on port 3000. The FastAPI app is defined in
openhands/server/listen.py, which sets up WebSocket endpoints for real-time
communication with the React frontend and REST endpoints for session management.
3. V1 Application Server
File: openhands/app_server/v1_router.py:1-20
router = APIRouter(prefix='/api/v1')
router.include_router(event_router.router)
router.include_router(app_conversation_router.router)
router.include_router(sandbox_router.router)
router.include_router(sandbox_spec_router.router)
router.include_router(user_router.router)
router.include_router(webhook_router.router)
router.include_router(web_client_router.router)The V1 server uses a modular router structure under /api/v1 with dedicated
sub-routers for conversations, events, sandboxes, users, and webhooks. The V1
agentic core is powered by the external
Software Agent SDK.
Complete Execution Pipeline
The following 10-step flow describes what happens from user input to completion. This applies to both CLI and web server paths (they converge at step 2).
┌─────────────────────────────────────────────────────────────────┐
│ EXECUTION PIPELINE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. USER INPUT │
│ CLI: parse_arguments() → read_task() → MessageAction │
│ Web: WebSocket message → MessageAction │
│ │ │
│ 2. INITIALIZATION ▼ │
│ run_controller() creates: │
│ • LLMRegistry + ConversationStats │
│ • Agent (via create_agent) │
│ • Runtime (Docker/Remote/Local/K8s/CLI) │
│ • EventStream (from runtime) │
│ • Memory (microagents, repo context) │
│ • AgentController │
│ │ │
│ 3. EVENT LOOP ▼ │
│ run_agent_until_done() polls controller state │
│ until an end state is reached │
│ │ │
│ 4. AGENT STEP ▼ │
│ AgentController._step() │
│ • Check state == RUNNING │
│ • Check no pending action │
│ • Run stuck detection │
│ • Run control flags (iteration/budget limits) │
│ • Call agent.step(state) │
│ │ │
│ 5. LLM CALL ▼ │
│ CodeActAgent.step(): │
│ • Condense history (via Condenser) │
│ • Build messages (ConversationMemory) │
│ • LLM completion (with tools) │
│ • Parse response → Action(s) │
│ │ │
│ 6. ACTION EXECUTION ▼ │
│ EventStream dispatches action to Runtime │
│ • Runtime.run() for CmdRunAction │
│ • Runtime.edit() for FileEditAction │
│ • Runtime.browse_interactive() for browser actions │
│ • etc. │
│ │ │
│ 7. OBSERVATION ▼ │
│ Runtime produces Observation, added to EventStream │
│ • CmdOutputObservation │
│ • FileReadObservation │
│ • ErrorObservation │
│ • BrowserOutputObservation │
│ │ │
│ 8. FEEDBACK LOOP ▼ │
│ Controller receives observation via on_event() │
│ → clears pending action │
│ → triggers next _step() if agent is RUNNING │
│ → loops back to step 4 │
│ │ │
│ 9. TERMINAL STATES ▼ │
│ Agent emits AgentFinishAction → FINISHED │
│ Agent emits AgentRejectAction → REJECTED │
│ Error occurs → ERROR │
│ User stops → STOPPED │
│ Stuck detection → ERROR (AgentStuckInLoopError) │
│ │ │
│ 10. CLEANUP ▼ │
│ • Save state to FileStore │
│ • Save trajectory (if configured) │
│ • Close controller, event stream, runtime │
│ │
└─────────────────────────────────────────────────────────────────┘
Key source references:
run_controller():openhands/core/main.py:59-319run_agent_until_done():openhands/core/loop.pyAgentController._step():openhands/controller/agent_controller.py:860-973CodeActAgent.step():openhands/agenthub/codeact_agent/codeact_agent.py:169-229
Agent State Machine
The AgentState enum (openhands/core/schema/agent.py:11-58) defines all
possible states. Below is the state transition diagram:
┌──────────────┐
│ LOADING │
└──────┬───────┘
│ initialization complete
▼
┌─────────────────────────────┐
┌─────────│ RUNNING │◄────────────────┐
│ └──┬──────┬──────┬──────┬──────┘ │
│ │ │ │ │ │
│ agent │ user│ con-│ er- │ stuck │
│ finish │ msg │ firm│ ror │ detect │
│ │ │ │ │ │
│ ▼ │ ▼ ▼ │
│ ┌──────────┐ │ ┌────────┐ ┌────────┐ │
│ │ FINISHED │ │ │AWAITING│ │ ERROR │──── resume ──┘
│ └──────────┘ │ │ USER │ └────────┘
│ │ │CONFIRM │
│ ┌──────────┐ │ └───┬────┘
│ │ REJECTED │ │ │ confirmed / rejected
│ └──────────┘ │ ▼
│ │ ┌────────────┐ ┌────────────┐
│ │ │ USER │ │ USER │
│ │ │ CONFIRMED │ │ REJECTED │
│ │ └─────┬──────┘ └─────┬──────┘
│ │ │ re-run action │ → AWAITING_USER_INPUT
│ │ └────────────────►│
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ AWAITING │◄────────────────┘
│ │ USER_INPUT │
│ └──────┬───────┘
│ │ user sends message
│ └─────────► RUNNING
│
│ ┌──────────┐
│ │ PAUSED │ ◄── user pause / loop detection
│ └──────┬───┘
│ │ user resume
│ └─────────► RUNNING
│
│ ┌──────────┐
└───────────►│ STOPPED │ ◄── user stop / ctrl+C
└──────────┘
┌──────────────┐
│ RATE_LIMITED │ ◄── LLM rate limit (transient)
└──────────────┘
State Descriptions
| State | Value | Description |
|---|---|---|
LOADING |
loading |
Agent is initializing |
RUNNING |
running |
Agent is actively processing |
AWAITING_USER_INPUT |
awaiting_user_input |
Agent asked a question, waiting for user |
AWAITING_USER_CONFIRMATION |
awaiting_user_confirmation |
Confirmation mode: risky action needs approval |
USER_CONFIRMED |
user_confirmed |
User approved the pending action |
USER_REJECTED |
user_rejected |
User rejected the pending action |
PAUSED |
paused |
Agent paused (user-initiated or loop detection) |
STOPPED |
stopped |
Agent stopped (terminal) |
FINISHED |
finished |
Agent completed the task (terminal) |
REJECTED |
rejected |
Agent rejected the task (terminal) |
ERROR |
error |
An error occurred (terminal, but can resume) |
RATE_LIMITED |
rate_limited |
LLM rate limit hit (transient) |