Skip to main content

Run Mode

The RunMode provides autonomous operation capabilities for the Penguin AI assistant, allowing it to switch from interactive conversation to task-driven execution mode.

Overview

Run Mode enables Penguin to:

  • Execute specific tasks with defined goals
  • Run continuously to process multiple tasks
  • Maintain workspace state across tasks
  • Operate with time limits and graceful shutdowns

Task Execution Flow (_execute_task)

The core logic for executing a task within RunMode resides in the _execute_task method.

  1. Check for Engine: It first checks if the PenguinCore instance has an initialized Engine.
  2. Delegate to Engine (Preferred): If the Engine exists, _execute_task delegates the entire multi-step reasoning and action loop to Engine.run_task(task_prompt_full, max_iterations=self.max_iterations). The Engine handles the iterations, LLM calls, action execution, and stop conditions.
  3. Legacy Fallback: If the Engine is not available (e.g., failed initialization), _execute_task falls back to its internal legacy loop:
    • It prepares the initial task prompt and adds it to the conversation.
    • It iterates up to max_iterations:
      • Calls PenguinCore.get_response() to get the next LLM response and potential actions based on the current conversation state.
      • Displays assistant output and action results.
      • Checks for completion or stop phrases in the response.
      • Continues the loop, building upon the conversation history.
  4. Handle Completion/Error: Returns the final status (completed, interrupted, error) and message.

Continuous Mode Operation

Initialization

def __init__(
self,
core,
max_iterations: int = MAX_TASK_ITERATIONS,
time_limit: Optional[int] = None,
):

Parameters:

  • core: PenguinCore instance to use for operations. RunMode will use core.engine if available.
  • max_iterations: Maximum iterations per task (used primarily in legacy fallback loop). Default from config.
  • time_limit: Optional time limit in minutes for continuous mode.

Key Methods

Start Single Task

async def start(
self,
name: str,
description: Optional[str] = None,
context: Optional[Dict[str, Any]] = None,
) -> None

Starts autonomous execution for a specific task by calling _execute_task.

Start Continuous Mode

async def start_continuous(self, specified_task_name: Optional[str] = None, task_description: Optional[str] = None) -> None:

Starts continuous operation mode that processes tasks sequentially, calling _execute_task for each task.

Task Execution (_execute_task)

async def _execute_task(
self,
name: str,
description: Optional[str] = None,
context: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]

Executes a task. Crucially, this method now attempts to delegate the entire execution loop to PenguinCore.engine.run_task if the Engine is available. If not, it falls back to its internal iterative loop using PenguinCore.get_response. Returns a dictionary with the task status and final message.

Task Completion & Control Phrases

RunMode uses special phrases, typically checked within the Engine loop or the legacy fallback loop, to manage task flow:

  • TASK_COMPLETION_PHRASE (e.g., "TASK_COMPLETED"): Signals that a specific task's objective has been met.
  • CONTINUOUS_COMPLETION_PHRASE (e.g., "CONTINUOUS_MODE_COMPLETE"): Signals the end of the entire continuous mode session (not just one task).
  • NEED_USER_CLARIFICATION_PHRASE (e.g., "NEED_USER_CLARIFICATION"): Indicates the AI needs more input from the user to proceed with the current task. This typically pauses the continuous mode.
  • EMERGENCY_STOP_PHRASE: Signals immediate termination of operations.

Task Flow Summary

When running a task (start or within start_continuous), RunMode primarily:

  1. Retrieves or prepares task details (name, description, context).
  2. Calls _execute_task.
  3. _execute_task checks for core.engine.
  4. If Engine exists: Delegates to Engine.run_task to handle the multi-step process until completion, stop condition, or error.
  5. If Engine doesn't exist: Initiates its own loop, calling core.get_response iteratively, checking for completion phrases itself.
  6. Handles the result (success, error, interruption, clarification needed).
  7. In continuous mode, loops to get the next task.

Continuous Mode

In continuous mode, RunMode:

  1. Initializes with a time limit if specified
  2. Enters a loop that:
    • Gets the next highest priority task from project manager
    • Executes the task
    • Marks task as complete when finished
    • Performs health checks periodically
    • Handles interruptions gracefully
  3. Monitors for shutdown requests
  4. Performs graceful shutdown when time limit is reached or shutdown requested

Health Monitoring

RunMode periodically checks system health:

async def _health_check(self) -> None

This monitors memory usage, CPU usage, and other diagnostic metrics to ensure stable operation.

Graceful Shutdown

async def _graceful_shutdown(self) -> None

Ensures clean shutdown by:

  • Completing current task if possible
  • Saving state information
  • Cleaning up resources
  • Logging shutdown information

Example Usage

# Create a RunMode instance
run_mode = RunMode(core, time_limit=60) # 60 minute limit

# Run a specific task
await run_mode.start(
name="build_data_parser",
description="Create a parser for CSV data files"
)

# Run in continuous mode to process tasks automatically
await run_mode.start_continuous()

Command Line Usage

RunMode is activated through slash commands inside the Penguin CLI:

penguin               # start the CLI
/run task build_data_parser "Create a parser for CSV files"

# Start continuous mode for 2 hours
/run --247 --time 120

Integration with Task Manager

RunMode integrates with the ProjectManager to:

  1. Retrieve task details by name
  2. Mark tasks as complete when finished
  3. Get the next highest priority task in continuous mode
  4. Track metadata for completed tasks

This allows for a seamless workflow where tasks can be created interactively and then executed autonomously.

DAG-Based Task Selection

When a project has tasks created from a Blueprint, RunMode uses DAG-based scheduling instead of simple priority ordering:

Tie-Breaker Order

When multiple tasks are ready (no pending dependencies), selection uses:

  1. Priority - critical > high > medium > low
  2. Value/Effort ratio - Higher value, lower effort wins (WSJF)
  3. Risk - Higher risk first (fail fast principle)
  4. Sequence - Explicit ordering from blueprint

Example

# In continuous mode with a Blueprint-synced project
await run_mode.start_continuous()

# RunMode will:
# 1. Check if project has a DAG
# 2. Get tasks with no pending dependencies
# 3. Apply tie-breakers to select next task
# 4. Execute task through ITUV workflow
# 5. Mark task complete, update DAG
# 6. Repeat until no tasks remain

ITUV Workflow Integration

RunMode can execute tasks through the ITUV (Implement, Test, Use, Verify) lifecycle when orchestration is enabled:

Enabling ITUV

# config.yml
orchestration:
backend: native # or "temporal" for durability
phase_timeouts:
implement: 600
test: 300
use: 180
verify: 120

Workflow Commands

# Start ITUV workflow for a specific task
/workflow start task-123

# Check workflow status
/workflow status ituv-task-123-abc

# Pause/resume/cancel
/workflow pause ituv-task-123-abc
/workflow resume ituv-task-123-abc
/workflow cancel ituv-task-123-abc

See Orchestration for detailed workflow documentation.

See Also