Skip to main content

Overview

UsePlanningSubagent exposes planning as a tool (plan_with_subagent) that the parent agent can call before implementation. The parent generates a task specification, the planner subagent can use an isolated tool set, and it returns a dense markdown plan back to the parent for execution. This pattern provides:
  • Planner isolation: planning runs in a separate subagent context
  • Tool scoping: planner tools can differ from the parent tool set
  • No recursion: planner toolset automatically removes spawn_subagent and plan_with_subagent
  • Prompt-level guidance: capability appends instructions describing required specification sections
Key concepts:
  • UsePlanningSubagent: installs plan_with_subagent and planning instructions
  • parentInstructions: system prompt fragment telling the parent when/how to call planner
  • parent tool constraints: listed in system prompt so plans stay executable
  • plannerSystemPrompt: specialist prompt for the planning subagent
  • plannerTools: optional allowlist of tools available to planner subagent
  • plannerAdditionalTools: planner-only tools not available to parent execution
  • plannerBudget: optional guard budget for the planner execution

Example

<?php
require 'examples/boot.php';

use Cognesy\Agents\Builder\AgentBuilder;
use Cognesy\Agents\Capability\Bash\BashTool;
use Cognesy\Agents\Capability\Core\UseGuards;
use Cognesy\Agents\Capability\Core\UseTools;
use Cognesy\Agents\Capability\File\ListDirTool;
use Cognesy\Agents\Capability\File\ReadFileTool;
use Cognesy\Agents\Capability\File\SearchFilesTool;
use Cognesy\Agents\Capability\PlanningSubagent\UsePlanningSubagent;
use Cognesy\Agents\Collections\NameList;
use Cognesy\Agents\Collections\Tools;
use Cognesy\Agents\Data\AgentState;
use Cognesy\Agents\Data\ExecutionBudget;
use Cognesy\Agents\Enums\ExecutionStatus;
use Cognesy\Agents\Events\Support\AgentEventConsoleObserver;
use Cognesy\Messages\Messages;

$logger = new AgentEventConsoleObserver(
    useColors: true,
    showTimestamps: true,
    showContinuation: true,
    showToolArgs: true,
);

$workDir = dirname(__DIR__, 3);
$parentExecutionTools = ['read_file'];
$parentToolsList = implode(', ', $parentExecutionTools);

$agent = AgentBuilder::base()
    ->withCapability(new UseTools(
        ReadFileTool::inDirectory($workDir),
    ))
    ->withCapability(new UsePlanningSubagent(
        parentInstructions: <<<PROMPT
For tasks that involve multiple implementation steps, call `plan_with_subagent` first.

Parent execution tools available (hard constraint): {$parentToolsList}

When you execute after planning, use only the parent execution tools listed above.

When calling `plan_with_subagent`, provide a task specification with these sections:
- Goal
- Context
- Constraints
- Expected Outcomes
- Acceptance Criteria
PROMPT,
        plannerSystemPrompt: <<<PROMPT
You are a planning specialist.
Create a dense markdown plan with explicit checkpoints and tool-aware execution steps.
Use discovery tools (`bash`, `search_files`, `list_dir`) to inspect local context if needed.
Use `bash` with `rg` for fast discovery when helpful.
Do not implement changes.

Parent execution tools (must be respected by the final plan): {$parentToolsList}
All execution steps in the final plan must be feasible using only those parent tools.
PROMPT,
        plannerTools: new NameList('bash', 'search_files', 'list_dir', 'read_file'),
        plannerAdditionalTools: new Tools(
            BashTool::inDirectory($workDir),
            SearchFilesTool::inDirectory($workDir),
            ListDirTool::inDirectory($workDir),
        ),
        plannerBudget: new ExecutionBudget(maxSteps: 3, maxTokens: 3072, maxSeconds: 30),
    ))
    ->withCapability(new UseGuards(maxSteps: 8, maxTokens: 12288, maxExecutionTime: 90))
    ->build()
    ->wiretap($logger->wiretap());

$task = <<<'TASK'
Prepare a realistic plan for a small docs update about planning capability in this repository.

First, create a plan.
Then execute only the analysis part of the plan and provide a concise proposal:
1. Capability purpose section outline
2. Configuration options outline
3. Example usage outline

Constraints:
- planner subagent may use bash/search for discovery
- parent execution may use only read_file
- do not modify any files
- keep the final response under 180 words
TASK;

$state = AgentState::empty()->withMessages(
    Messages::fromString($task)
);

echo "=== Agent Execution Log ===\n";
echo "Task: Plan first, then execute\n\n";

$finalState = $agent->execute($state);

echo "\n=== Result ===\n";
$answer = $finalState->finalResponse()->toString() ?: 'No answer';
echo "Answer: {$answer}\n";
echo "Steps: {$finalState->stepCount()}\n";
echo "Tokens: {$finalState->usage()->total()}\n";
echo "Status: {$finalState->status()->value}\n";

if ($finalState->status()->value === 'failed') {
    echo "Skipping assertions because execution status is failed.\n";
    return;
}

$hasAnswer = trim($finalState->finalResponse()->toString()) !== '';
$isStopped = $finalState->status() === ExecutionStatus::Stopped;
assert($hasAnswer || $isStopped, 'Expected non-empty response or stopped status');
assert($finalState->stepCount() >= 1, 'Expected at least 1 step');
assert($finalState->usage()->total() > 0, 'Expected token usage > 0');
?>