Agent Options
Introduction¶
Agent-Ctrl's builder API is split into two layers: a shared set of methods that every builder supports, and agent-specific methods that expose the unique capabilities of each CLI tool. This design lets you write agent-agnostic code for common configuration while still accessing the full feature set of each agent when needed.
All configuration methods return static, so they can be chained fluently in any order before calling execute() or executeStreaming().
Shared Options¶
The following methods are defined in the AgentBridgeBuilder interface and implemented by every bridge builder. They work identically regardless of which agent you are using.
withConfig(AgentCtrlConfig $config): static¶
Apply a typed config object containing the shared builder options:
use Cognesy\AgentCtrl\Config\AgentCtrlConfig;
$config = AgentCtrlConfig::fromArray([
'model' => 'claude-sonnet-4-5',
'timeout' => 300,
'directory' => '/projects/my-app',
'sandbox' => 'docker',
]);
AgentCtrl::claudeCode()
->withConfig($config)
->execute('Review the payment flow.');
// @doctest id="1a99"
This is the preferred way to pass shared builder defaults around your own application code. The object covers:
modeltimeoutworkingDirectorysandboxDriver
withModel(string $model): static¶
Set the model the agent should use. The accepted model name format depends on the agent:
// Claude Code: Anthropic model names
AgentCtrl::claudeCode()->withModel('claude-sonnet-4-5');
// Codex: OpenAI model names
AgentCtrl::codex()->withModel('o4-mini');
// OpenCode: provider/model format
AgentCtrl::openCode()->withModel('anthropic/claude-sonnet-4-5');
// @doctest id="acb6"
If not specified, each agent uses its own default model.
withTimeout(int $seconds): static¶
Set the maximum execution time in seconds. The default is 120 seconds. The minimum accepted value is 1 second -- values below 1 are clamped.
AgentCtrl::claudeCode()
->withTimeout(600) // 10 minutes for complex tasks
->execute('Perform a comprehensive codebase review.');
// @doctest id="4200"
When the timeout is reached, the sandbox executor kills the process. The response will contain whatever output was produced before the timeout and will have a non-zero exit code.
inDirectory(string $path): static¶
Set the working directory for the agent. The bridge validates that the directory exists before execution and throws an InvalidArgumentException if it does not.
AgentCtrl::codex()
->inDirectory('/projects/my-app')
->execute('List the source files.');
// @doctest id="64ab"
Always use absolute paths. The bridge changes the PHP process's current working directory for the duration of the execution and restores it afterward.
withSandboxDriver(SandboxDriver $driver): static¶
Set the sandbox driver for process isolation. The default is SandboxDriver::Host, which runs the CLI binary directly on the host system.
use Cognesy\Sandbox\Enums\SandboxDriver;
AgentCtrl::claudeCode()
->withSandboxDriver(SandboxDriver::Docker)
->execute('Analyze this codebase.');
// @doctest id="959e"
Available drivers: Host, Docker, Podman, Firejail, Bubblewrap.
Streaming Callbacks¶
Four callback methods are shared across all builders. See the Streaming documentation for full details.
onText(callable $handler): static-- Receive incremental text outputonToolUse(callable $handler): static-- Receive normalized tool call eventsonComplete(callable $handler): static-- Receive the finalAgentResponseonError(callable $handler): static-- Receive streamed error events
wiretap(callable $handler): static¶
Connect an event observer to the builder's internal event system. This is primarily used with the AgentCtrlConsoleLogger for development-time debugging:
use Cognesy\AgentCtrl\Broadcasting\AgentCtrlConsoleLogger;
$logger = new AgentCtrlConsoleLogger(showStreaming: true);
AgentCtrl::claudeCode()
->wiretap($logger->wiretap())
->execute('Review this code.');
// @doctest id="6506"
build(): AgentBridge¶
Build the configured bridge without executing a prompt. This is an advanced method for scenarios where you need to call the bridge's execute() or executeStreaming() methods directly:
use Cognesy\AgentCtrl\Config\AgentCtrlConfig;
$bridge = AgentCtrl::claudeCode()
->withConfig(new AgentCtrlConfig(
model: 'claude-sonnet-4-5',
timeout: 300,
))
->build();
$response = $bridge->execute('First prompt.');
$response2 = $bridge->executeStreaming('Second prompt.', $streamHandler);
// @doctest id="9f96"
Claude Code Options¶
The ClaudeCodeBridgeBuilder adds the following methods on top of the shared options.
withSystemPrompt(string|\Stringable $prompt): static¶
Replace the agent's default system prompt entirely with a custom one:
AgentCtrl::claudeCode()
->withSystemPrompt('You are a security auditor. Focus on vulnerabilities.')
->execute('Audit the authentication module.');
// @doctest id="4e55"
appendSystemPrompt(string|\Stringable $prompt): static¶
Add instructions on top of the default system prompt without replacing it. This preserves Claude Code's built-in behavior while layering in project-specific context:
AgentCtrl::claudeCode()
->appendSystemPrompt('This project uses Laravel conventions. Follow PSR-12.')
->execute('Refactor the UserService class.');
// @doctest id="236f"
You can use both withSystemPrompt() and appendSystemPrompt() together -- withSystemPrompt() sets the base and appendSystemPrompt() appends to it. Both accept Stringable objects (e.g. xprompt Prompt classes), which are cast to string at the boundary.
withMaxTurns(int $turns): static¶
Limit the number of agentic turns. Each turn represents one cycle where the agent reads context, reasons, and takes an action. The minimum is 1.
AgentCtrl::claudeCode()
->withMaxTurns(10)
->execute('Make a focused improvement to the README.');
// @doctest id="633c"
Without a turn limit, Claude Code continues working until it decides the task is complete or the timeout is reached. For simple tasks, 5-10 turns is often sufficient. Complex refactoring may need 20-50 turns.
withPermissionMode(PermissionMode $mode): static¶
Control how the agent handles tool permission requests during headless execution. The default is BypassPermissions because Agent-Ctrl runs headlessly and cannot respond to interactive permission prompts.
use Cognesy\AgentCtrl\ClaudeCode\Domain\Enum\PermissionMode;
AgentCtrl::claudeCode()
->withPermissionMode(PermissionMode::AcceptEdits)
->execute('Write unit tests for the PaymentService.');
// @doctest id="3d74"
| Mode | Behavior |
|---|---|
PermissionMode::DefaultMode |
Standard interactive prompts. Not suitable for headless execution. |
PermissionMode::Plan |
Agent can plan and reason but prompts before executing any tool. |
PermissionMode::AcceptEdits |
Auto-approve file editing tools; prompt for shell commands and other actions. |
PermissionMode::BypassPermissions |
Auto-approve all tool uses without prompting (default). |
verbose(bool $enabled = true): static¶
Enable or disable verbose output. Verbose mode is required for proper stream-JSON parsing and is enabled by default. You generally do not need to change this setting.
continueSession(): static¶
Continue the most recent Claude Code session. See Session Management.
resumeSession(string $sessionId): static¶
Resume a specific Claude Code session by its ID. See Session Management.
withAdditionalDirs(array $paths): static¶
Grant the agent access to additional directories beyond the working directory:
AgentCtrl::claudeCode()
->inDirectory('/projects/my-app')
->withAdditionalDirs(['/shared/libraries', '/configs/production'])
->execute('Update the app to use the latest shared auth library.');
// @doctest id="6257"
Complete Claude Code Example¶
use Cognesy\AgentCtrl\AgentCtrl;
use Cognesy\AgentCtrl\ClaudeCode\Domain\Enum\PermissionMode;
$response = AgentCtrl::claudeCode()
->withModel('claude-sonnet-4-5')
->withSystemPrompt('You are a careful code reviewer.')
->appendSystemPrompt('Focus on error handling and edge cases.')
->withPermissionMode(PermissionMode::BypassPermissions)
->withMaxTurns(15)
->withTimeout(300)
->inDirectory('/projects/my-app')
->withAdditionalDirs(['/shared/utils'])
->onText(fn(string $text) => print($text))
->executeStreaming('Review the PaymentService for error handling issues.');
// @doctest id="8293"
Codex Options¶
The CodexBridgeBuilder adds the following methods on top of the shared options.
withSandbox(SandboxMode $mode): static¶
Set the Codex sandbox mode, which controls filesystem and network access:
use Cognesy\AgentCtrl\OpenAICodex\Domain\Enum\SandboxMode;
AgentCtrl::codex()
->withSandbox(SandboxMode::WorkspaceWrite)
->execute('Write tests for the UserService.');
// @doctest id="80a0"
| Mode | Filesystem | Network |
|---|---|---|
SandboxMode::ReadOnly |
Read-only access | No |
SandboxMode::WorkspaceWrite |
Write access to workspace only | No |
SandboxMode::DangerFullAccess |
Full access | Yes |
disableSandbox(): static¶
Shorthand for withSandbox(SandboxMode::DangerFullAccess). Provides full filesystem and network access:
AgentCtrl::codex()
->disableSandbox()
->execute('Install dependencies and run the test suite.');
// @doctest id="605a"
fullAuto(bool $enabled = true): static¶
Enable full-auto mode, which combines workspace-write sandbox access with automatic on-failure approval. This is enabled by default for headless execution:
dangerouslyBypass(bool $enabled = true): static¶
Skip all approval prompts and sandbox restrictions. This is the most permissive mode and should be used with caution:
skipGitRepoCheck(bool $enabled = true): static¶
Allow the agent to run outside a Git repository. By default, Codex requires the working directory to be inside a Git repository:
AgentCtrl::codex()
->skipGitRepoCheck()
->inDirectory('/tmp/workspace')
->execute('Create a new project skeleton.');
// @doctest id="d814"
withImages(array $imagePaths): static¶
Attach image files to the prompt for visual analysis:
AgentCtrl::codex()
->withImages(['/tmp/mockup.png', '/tmp/screenshot.png'])
->execute('Implement the UI shown in the mockup images.');
// @doctest id="83e9"
continueSession(): static¶
Continue the most recent Codex session. See Session Management.
resumeSession(string $sessionId): static¶
Resume a specific Codex session by its thread ID. See Session Management.
withAdditionalDirs(array $paths): static¶
Add additional writable directories for the Codex agent:
AgentCtrl::codex()
->withAdditionalDirs(['/shared/assets'])
->execute('Update the shared configuration.');
// @doctest id="a038"
Complete Codex Example¶
use Cognesy\AgentCtrl\AgentCtrl;
use Cognesy\AgentCtrl\OpenAICodex\Domain\Enum\SandboxMode;
$response = AgentCtrl::codex()
->withModel('o4-mini')
->withSandbox(SandboxMode::WorkspaceWrite)
->fullAuto()
->withTimeout(300)
->inDirectory('/projects/my-app')
->withImages(['/tmp/design-spec.png'])
->onText(fn(string $text) => print($text))
->executeStreaming('Implement the component shown in the design spec.');
// @doctest id="eb69"
OpenCode Options¶
The OpenCodeBridgeBuilder adds the following methods on top of the shared options.
withAgent(string $agentName): static¶
Select a named agent within OpenCode (e.g., 'coder', 'task'):
AgentCtrl::openCode()
->withAgent('coder')
->execute('Refactor the authentication module.');
// @doctest id="8cc1"
withFiles(array $filePaths): static¶
Attach specific files to the prompt for the agent to reference:
AgentCtrl::openCode()
->withFiles(['/projects/my-app/src/UserService.php'])
->execute('Review this file for potential issues.');
// @doctest id="2b6e"
withTitle(string $title): static¶
Set a descriptive title for the session, which appears in OpenCode's session listing:
AgentCtrl::openCode()
->withTitle('Payment module refactoring')
->execute('Plan the payment module refactoring.');
// @doctest id="e77c"
shareSession(): static¶
Mark the session for sharing after completion, making it accessible to other users or tools:
AgentCtrl::openCode()
->shareSession()
->execute('Create a code review summary.');
// @doctest id="680c"
continueSession(): static¶
Continue the most recent OpenCode session. See Session Management.
resumeSession(string $sessionId): static¶
Resume a specific OpenCode session by its ID. See Session Management.
Complete OpenCode Example¶
use Cognesy\AgentCtrl\AgentCtrl;
$response = AgentCtrl::openCode()
->withModel('anthropic/claude-sonnet-4-5')
->withAgent('coder')
->withTitle('Architecture review')
->withFiles(['/projects/my-app/src/Kernel.php'])
->withTimeout(300)
->inDirectory('/projects/my-app')
->onText(fn(string $text) => print($text))
->executeStreaming('Review the application architecture.');
if ($response->cost() !== null) {
echo sprintf("\nCost: $%.4f\n", $response->cost());
}
// @doctest id="16b3"
Pi Options¶
The PiBridgeBuilder adds the following methods on top of the shared options.
withProvider(string $provider): static¶
Set the provider explicitly (e.g., 'anthropic', 'openai', 'google'):
AgentCtrl::pi()
->withProvider('anthropic')
->execute('Analyze this codebase.');
// @doctest id="ac62"
withThinking(ThinkingLevel $level): static¶
Set the thinking level, which controls how much reasoning the agent does:
use Cognesy\AgentCtrl\Pi\Domain\Enum\ThinkingLevel;
AgentCtrl::pi()
->withThinking(ThinkingLevel::High)
->execute('Solve this complex problem.');
// @doctest id="82fc"
| Level | Value |
|---|---|
ThinkingLevel::Off |
'off' |
ThinkingLevel::Minimal |
'minimal' |
ThinkingLevel::Low |
'low' |
ThinkingLevel::Medium |
'medium' |
ThinkingLevel::High |
'high' |
ThinkingLevel::ExtraHigh |
'xhigh' |
withSystemPrompt(string|\Stringable $prompt): static¶
Replace the agent's default system prompt:
AgentCtrl::pi()
->withSystemPrompt('You are a security auditor.')
->execute('Audit the authentication module.');
// @doctest id="6e1b"
appendSystemPrompt(string|\Stringable $prompt): static¶
Add instructions on top of the default system prompt:
AgentCtrl::pi()
->appendSystemPrompt('Focus on PSR-12 compliance.')
->execute('Review this code.');
// @doctest id="7201"
withTools(array $tools): static¶
Enable specific built-in tools:
AgentCtrl::pi()
->withTools(['read', 'bash', 'edit'])
->execute('Refactor this file.');
// @doctest id="74b0"
noTools(): static¶
Disable all built-in tools.
withFiles(array $filePaths): static¶
Attach files to the prompt:
AgentCtrl::pi()
->withFiles(['/projects/my-app/src/UserService.php'])
->execute('Review this file.');
// @doctest id="590f"
withExtensions(array $extensions): static¶
Load extensions from paths or sources.
noExtensions(): static¶
Disable extension discovery.
withSkills(array $skills): static¶
Load skills from paths.
noSkills(): static¶
Disable skill discovery.
withApiKey(string $apiKey): static¶
Override the API key for this execution.
ephemeral(): static¶
Run in ephemeral mode -- the session is not saved.
withSessionDir(string $dir): static¶
Set a custom session storage directory.
verbose(bool $enabled = true): static¶
Enable verbose output.
continueSession(): static¶
Continue the most recent Pi session. See Session Management.
resumeSession(string $sessionId): static¶
Resume a specific Pi session by its ID. See Session Management.
Complete Pi Example¶
use Cognesy\AgentCtrl\AgentCtrl;
use Cognesy\AgentCtrl\Pi\Domain\Enum\ThinkingLevel;
$response = AgentCtrl::pi()
->withProvider('anthropic')
->withThinking(ThinkingLevel::High)
->withSystemPrompt('You are a careful code reviewer.')
->withTools(['read', 'bash'])
->withTimeout(300)
->inDirectory('/projects/my-app')
->onText(fn(string $text) => print($text))
->executeStreaming('Review the PaymentService for edge cases.');
// @doctest id="66af"
Gemini Options¶
The GeminiBridgeBuilder adds the following methods on top of the shared options.
withApprovalMode(ApprovalMode $mode): static¶
Set the approval mode for tool execution:
use Cognesy\AgentCtrl\Gemini\Domain\Enum\ApprovalMode;
AgentCtrl::gemini()
->withApprovalMode(ApprovalMode::Yolo)
->execute('Refactor the database layer.');
// @doctest id="b271"
| Mode | Value | Behavior |
|---|---|---|
ApprovalMode::Default |
'default' |
Standard interactive prompts |
ApprovalMode::AutoEdit |
'auto_edit' |
Auto-approve edits, prompt for others |
ApprovalMode::Yolo |
'yolo' |
Auto-approve all actions |
ApprovalMode::Plan |
'plan' |
Read-only analysis mode |
yolo(): static¶
Shorthand for withApprovalMode(ApprovalMode::Yolo):
planMode(): static¶
Shorthand for withApprovalMode(ApprovalMode::Plan):
AgentCtrl::gemini()
->planMode()
->execute('Analyze the codebase architecture.');
// @doctest id="6d78"
withSandbox(bool $enabled = true): static¶
Enable Gemini's sandbox mode for additional isolation.
withIncludeDirectories(array $paths): static¶
Add additional workspace directories:
AgentCtrl::gemini()
->withIncludeDirectories(['/shared/libraries', '/configs'])
->execute('Review the shared library usage.');
// @doctest id="1bd5"
withExtensions(array $extensions): static¶
Use specific extensions.
withAllowedTools(array $tools): static¶
Restrict which tools the agent can use:
AgentCtrl::gemini()
->withAllowedTools(['read_file', 'search_files', 'list_directory'])
->execute('Analyze the codebase structure.');
// @doctest id="87cc"
withAllowedMcpServers(array $names): static¶
Set allowed MCP server names.
withPolicy(array $paths): static¶
Add policy files or directories.
debug(bool $enabled = true): static¶
Enable debug output for troubleshooting CLI behavior.
continueSession(): static¶
Continue the most recent Gemini session (resumes 'latest' internally). See Session Management.
resumeSession(string $sessionId): static¶
Resume a specific Gemini session by its ID or index. See Session Management.
Complete Gemini Example¶
use Cognesy\AgentCtrl\AgentCtrl;
use Cognesy\AgentCtrl\Gemini\Domain\Enum\ApprovalMode;
$response = AgentCtrl::gemini()
->withApprovalMode(ApprovalMode::Yolo)
->withAllowedTools(['read_file', 'edit_file', 'shell'])
->withIncludeDirectories(['/shared/utils'])
->withTimeout(300)
->inDirectory('/projects/my-app')
->onText(fn(string $text) => print($text))
->executeStreaming('Review the authentication module.');
// @doctest id="68fc"