How PI-Desktop Manages Agent Workflows: From Interactive Chat to Sub-Agent Execution

PI-Desktop implements agent workflows through a three-mode lifecycle—agent, plan, and goal—that transitions users from interactive chat to structured plan approval, culminating in autonomous goal execution with optional sub-agent delegation.

The open-source PI-Desktop repository orchestrates complex AI delegation through a strict lifecycle defined in packages/shared/src/types.ts. This architecture separates interactive conversations from background task execution by enforcing a Markdown-based planning phase before any autonomous goal runs. Understanding these agent workflows is essential for developers extending the desktop client or integrating custom sub-agents.

The Three Modes of Agent Workflows

PI-Desktop drives its AI assistant through three distinct modes defined in the shared types package. Each mode represents a specific phase in the delegation lifecycle, governing how the model interacts with user input and system resources.

Agent Mode: The Default Interactive State

In agent mode, the system operates as a standard interactive chat interface. The Mode type is set to "agent", and the model answers user prompts directly without spawning background processes. This is the default state when no plan is pending or executing.

Plan Mode: Structured Approval Workflow

Plan mode introduces a validation gate before execution. When a user creates a plan—a Markdown document stored under ~/.agents/plans/…—the system sets ProposalKind = "plan" and transitions the PlanningState to "planning" or "awaiting_approval". The UI renders a plan editor, and upon submission, the proposal enters a pending approval queue. This phase ensures that potentially destructive or complex operations require explicit user consent before the runtime allocates resources.

Goal Mode: Autonomous Execution with Sub-Agents

Once approved, the proposal transitions to goal mode with ProposalKind = "goal". In this state, the main agent enters the sub-agent orchestration layer and may spawn sub-agents (also called subagents) to carry out parts of the work. These sub-agents run in their own execution turns and report lifecycle events (agent_start, agent_end, turn_end) tagged with agentName via the AgentActivityAgent interface.

The Plan-to-Goal Lifecycle Implementation

The transition from plan to goal involves several technical layers across the PI-Desktop codebase, from IPC communication to state normalization.

Creating and Submitting Plans

Users author plans as Markdown files in the ~/.agents/plans/ directory. When submitted, the desktop client sends the plan through the RACP (Remote Agent Control Protocol) using the plansPending and plansResolve IPC channels declared in packages/shared/src/protocol.ts. The host returns a raw execution response that must be normalized before use.

The normalizeProposalKind utility in packages/shared/src/types.ts ensures that the proposal kind is strictly typed as either "plan" or "goal":

import { normalizeProposalKind, ProposalKind } from "@pi-desktop/shared";

function getKind(raw: unknown): ProposalKind {
  // Accepts "plan", "goal", or any value and falls back to "plan"
  return normalizeProposalKind(raw);
}

Decoding Execution Records

The main process decodes host responses using the executionFromResponse function in apps/desktop/electron/main/plan-execution.ts. This normalizes the host-provided PlanExecution record, which contains:

  • id, proposalId, sessionId
  • kind ("plan" or "goal") normalized via normalizeProposalKind
  • targetPermissionMode normalized via normalizeGlobalPermissionMode
  • state values: "queued", "running", "completed", "interrupted"
import { executionFromResponse } from "./plan-execution";

const rawResponse = await ipcInvoke("plansResolve", { id: "123" });
const exec = executionFromResponse(rawResponse);

if (exec) {
  console.log(`Goal ${exec.id} is ${exec.state}`);
}

Sub-Agent Orchestration in Goal Mode

When a goal executes, the runtime (packages/agent-runtime/src/runtime.ts) manages sub-agents defined by Markdown files in ~/.agents/subagents/… (see SubagentDefinition in packages/shared/src/subagent-definition.ts).

Spawning Sub-Agents via the Task Tool

Parent agents spawn sub-agents through the Task tool, which generates events trackable across the system:

import { Task } from "@pi-desktop/agent-runtime";

await Task.call({
  tool: "subagent",
  args: {
    name: "explorer",
    input: "Search repository for TODO comments",
  },
});

Internally, the Task tool produces an event with type: "turn_end" and agentName: "explorer" (see AgentActivityAgent in packages/shared/src/types.ts).

Tracking and Permissions

The runtime tracks each sub-agent’s thinking level (SUBAGENT_THINKING_LEVELS) and permission (SUBAGENT_PERMISSIONS) to enforce sandbox boundaries and resource limits during goal execution.

State Management and Error Recovery

While a goal runs, the central session’s planningState is set to "inactive" (indicating the plan phase has concluded). The UI subscribes to the plansChanged IPC event (declared in packages/shared/src/protocol.ts) to render progress indicators. Upon completion, the state transitions to "completed" or "interrupted", and results are persisted to disk.

For resilience, the system implements provider-retry logic in packages/agent-runtime/src/provider-retry.ts alongside RACP timeout schemas (racp.ts). These mechanisms recover from transient host failures, allowing goals to resume if the connection drops during sub-agent execution.

Summary

  • Three distinct modes drive PI-Desktop: interactive agent chat, approval-gated plan creation, and autonomous goal execution.
  • Markdown-based plans stored in ~/.agents/plans/ require RACP validation through plansPending/plansResolve IPC channels before transitioning to goals.
  • Sub-agent orchestration occurs within goal mode, using the Task tool to spawn agents defined in ~/.agents/subagents/ with tracked permissions and thinking levels.
  • Resilient execution is ensured via normalizeProposalKind type safety, executionFromResponse decoding, and provider-retry logic for fault recovery.

Frequently Asked Questions

What is the difference between plan mode and goal mode in PI-Desktop?

Plan mode requires explicit approval before execution and operates with ProposalKind = "plan" and planning states of "planning" or "awaiting_approval". Goal mode represents active execution with ProposalKind = "goal", where the system spawns sub-agents and tracks execution states like "running" or "completed" via the PlanExecution type.

How does PI-Desktop validate plans before execution?

Validation occurs through the RACP (Remote Agent Control Protocol) using the plansPending and plansResolve IPC channels defined in packages/shared/src/protocol.ts. The host returns an execution record that is normalized through executionFromResponse in apps/desktop/electron/main/plan-execution.ts, ensuring type-safe state transitions.

Where are sub-agent definitions stored?

Sub-agent definitions are Markdown files located in the ~/.agents/subagents/ directory. The SubagentDefinition interface in packages/shared/src/subagent-definition.ts describes their schema, which the runtime uses when spawning agents via the Task tool during goal execution.

How does the system recover from failures during goal execution?

The runtime implements retry logic in packages/agent-runtime/src/provider-retry.ts and conforms to RACP timeout schemas in racp.ts. These components handle transient provider failures, ensuring that interrupted goals can resume without data loss if the host crashes or the connection drops.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →