LinuxAgent State Machine

November 12, 2025 · View on GitHub

LinuxAgent uses a 3-state finite state machine (FSM) to manage CLI task execution flow. The minimal state set captures essential execution progression while maintaining simplicity and predictability. States transition based on LLM decisions and command execution results.

State Machine Architecture

State Enumeration

class LinuxAgentStatus(Enum):
    """Store the status of the linux agent"""
    CONTINUE = "CONTINUE"  # Task is ongoing, requires further commands
    FINISH = "FINISH"      # Task completed successfully
    FAIL = "FAIL"          # Task cannot proceed, unrecoverable error

State Management

LinuxAgent states are managed by LinuxAgentStateManager, which implements the agent state registry pattern:

class LinuxAgentStateManager(AgentStateManager):
    """Manages the states of the linux agent"""
    _state_mapping: Dict[str, Type[LinuxAgentState]] = {}
    
    @property
    def none_state(self) -> AgentState:
        return NoneLinuxAgentState()

All LinuxAgent states are registered using the @LinuxAgentStateManager.register decorator, enabling dynamic state lookup by name.

State Transition Diagram

![LinuxAgent State Machine](../img/linux_agent_state.png)
Figure: Lifecycle state transitions of the LinuxAgent. The agent starts in CONTINUE state, executes CLI commands iteratively, and transitions to FINISH upon completion or FAIL upon encountering unrecoverable errors.

State Definitions

1. CONTINUE State

Purpose: Active execution state where LinuxAgent processes the user request and executes CLI commands.

@LinuxAgentStateManager.register
class ContinueLinuxAgentState(LinuxAgentState):
    """The class for the continue linux agent state"""
    
    async def handle(self, agent: "LinuxAgent", context: Optional["Context"] = None):
        """Execute the 3-phase processing pipeline"""
        await agent.process(context)
    
    def is_round_end(self) -> bool:
        return False  # Round continues
    
    def is_subtask_end(self) -> bool:
        return False  # Subtask continues
    
    @classmethod
    def name(cls) -> str:
        return LinuxAgentStatus.CONTINUE.value
PropertyValue
TypeActive
Processor Executed✓ Yes (3 phases)
Round EndsNo
Subtask EndsNo
DurationSingle round
Next StatesCONTINUE, FINISH, FAIL

Behavior:

  1. Constructs prompts with previous execution results
  2. Gets next CLI command from LLM
  3. Executes command via MCP server
  4. Updates memory with execution results
  5. Determines next state based on LLM response

State Transition Logic:

  • CONTINUE → CONTINUE: Task requires more commands to complete
  • CONTINUE → FINISH: LLM determines task is complete
  • CONTINUE → FAIL: Unrecoverable error encountered (e.g., permission denied, resource unavailable)

2. FINISH State

Purpose: Terminal state indicating successful task completion.

@LinuxAgentStateManager.register
class FinishLinuxAgentState(LinuxAgentState):
    """The class for the finish linux agent state"""
    
    def next_agent(self, agent: "LinuxAgent") -> "LinuxAgent":
        return agent
    
    def next_state(self, agent: "LinuxAgent") -> LinuxAgentState:
        return FinishLinuxAgentState()  # Remains in FINISH
    
    def is_subtask_end(self) -> bool:
        return True  # Subtask completed
    
    def is_round_end(self) -> bool:
        return True  # Round ends
    
    @classmethod
    def name(cls) -> str:
        return LinuxAgentStatus.FINISH.value
PropertyValue
TypeTerminal
Processor Executed✗ No
Round EndsYes
Subtask EndsYes
DurationPermanent
Next StatesFINISH (no transition)

Behavior:

  • Signals task completion to session manager
  • No further processing occurs
  • Agent instance can be terminated

FINISH state is reached when all required CLI commands have been executed successfully, the LLM determines the user request has been fulfilled, and no errors or exceptions occurred during execution.

3. FAIL State

Purpose: Terminal state indicating task failure due to unrecoverable errors.

@LinuxAgentStateManager.register
class FailLinuxAgentState(LinuxAgentState):
    """The class for the fail linux agent state"""
    
    def next_agent(self, agent: "LinuxAgent") -> "LinuxAgent":
        return agent
    
    def next_state(self, agent: "LinuxAgent") -> LinuxAgentState:
        return FinishLinuxAgentState()  # Transitions to FINISH for cleanup
    
    def is_round_end(self) -> bool:
        return True  # Round ends
    
    def is_subtask_end(self) -> bool:
        return True  # Subtask failed
    
    @classmethod
    def name(cls) -> str:
        return LinuxAgentStatus.FAIL.value
PropertyValue
TypeTerminal (Error)
Processor Executed✗ No
Round EndsYes
Subtask EndsYes
DurationTransitions to FINISH
Next StatesFINISH

Behavior:

  • Logs failure reason and context
  • Transitions to FINISH state for cleanup
  • Session manager receives failure status

!!!error "Failure Conditions" FAIL state is reached when insufficient privileges prevent command execution, required system resources are not accessible (disk full, network unreachable), repeated command syntax errors occur, the LLM explicitly indicates task cannot be completed, or task requirements exceed current system capabilities.

Error Recovery:

While FAIL is a terminal state, the error information is logged for debugging:

# Example error logging in FAIL state
agent.logger.error(f"Task failed: {error_message}")
agent.logger.debug(f"Last command: {last_command}")
agent.logger.debug(f"Command output: {stderr}")

State Transition Rules

Transition Decision Logic

State transitions are determined by the LLM's response in the CONTINUE state:

# LLM returns status in response
parsed_response = {
    "action": {
        "command": "df -h",
        "status": "CONTINUE"  # or "FINISH" or "FAIL"
    },
    "thought": "Need to check disk space first"
}

# Agent updates its status based on LLM decision
agent.status = parsed_response["action"]["status"]
next_state = LinuxAgentStateManager().get_state(agent.status)

Transition Matrix

Current StateConditionNext StateTrigger
CONTINUELLM returns CONTINUECONTINUEMore commands needed
CONTINUELLM returns FINISHFINISHTask completed
CONTINUELLM returns FAILFAILUnrecoverable error
CONTINUEException raisedFAILSystem error
FINISHAnyFINISHNo transition
FAILAnyFINISHCleanup transition

State-Specific Processing

CONTINUE State Processing Pipeline

When in CONTINUE state, LinuxAgent executes the full 3-phase pipeline:

graph TD
    A[CONTINUE State] --> B[Phase 1: LLM Interaction]
    B --> C[Phase 2: Action Execution]
    C --> D[Phase 3: Memory Update]
    D --> E{Check Status}
    E -->|CONTINUE| A
    E -->|FINISH| F[FINISH State]
    E -->|FAIL| G[FAIL State]

Terminal States (FINISH / FAIL)

Terminal states perform no processing:

  • FINISH: Clean termination, results available in memory
  • FAIL: Error termination, error details logged

Deterministic Control Flow

The 3-state design ensures deterministic, traceable execution with predictable behavior (every execution path is well-defined), debuggability (state transitions are logged and traceable), testability (finite state space simplifies testing), and maintainability (simple state set reduces complexity).

Comparison with Other Agents

AgentStatesComplexityUse Case
LinuxAgent3MinimalCLI task execution
AppAgent6ModerateWindows app automation
HostAgent7HighDesktop orchestration

LinuxAgent's minimal 3-state design reflects its focused scope: execute CLI commands to fulfill user requests. The simplified state machine eliminates unnecessary complexity while maintaining robust error handling and completion detection.

Implementation Details

The state machine implementation can be found in:

ufo/agents/states/linux_agent_state.py

Key classes:

  • LinuxAgentStatus: State enumeration
  • LinuxAgentStateManager: State registry and lookup
  • LinuxAgentState: Abstract base class
  • ContinueLinuxAgentState: Active execution state
  • FinishLinuxAgentState: Successful completion state
  • FailLinuxAgentState: Error termination state
  • NoneLinuxAgentState: Initial/undefined state

Next Steps

  • Processing Strategy - Understand the 3-phase processing pipeline executed in CONTINUE state
  • MCP Commands - Explore CLI command execution and system information retrieval
  • Overview - Return to LinuxAgent architecture overview