2-tool AI agent shell for PHP — vector discovery + CLI execution. Port of the Agent Shell pattern to native PHP.
composer require mauricioperera/php-agent-shell
Traditional AI agent frameworks register every tool individually. 50 tools = ~10,000 tokens of context in every request, even if the agent only uses 2.
PHPAgentShell exposes exactly 2 tools to the LLM:
Tool 1: cli_help() → Interaction protocol (~185 tokens, constant)
Tool 2: cli_exec(cmd: str) → Search, describe, execute any command
Commands are discovered via vector semantic search, not by listing all tools. The agent searches in natural language, describes what it finds, then executes.
Traditional: 19 tools × 200 tokens = 3,800 tokens PER REQUEST
Agent Shell: 2 tools × 100 tokens = 200 tokens ALWAYS (94% reduction)
use PHPAgentShell\AgentShell;
$shell = new AgentShell(
embedFn: fn(string $text) => myEmbedFunction($text),
dimensions: 768,
);
$shell->registerDefaults(); // 19 built-in commands
// The LLM gets the protocol (once)
$protocol = $shell->help(); // ~185 tokens
// The LLM interacts via exec()
$shell->exec('search list files');
// → [{name: "file:list", score: 0.98, description: "List files..."}]
$shell->exec('describe file:list');
// → {definition: {...}, help: "file:list -- List files... --path (required): ..."}
$shell->exec('file:list --path /my/project');
// → {entries: [{name: "src", type: "dir"}, ...], count: 7, code: 0}Step 1: LLM receives help() "Agent Shell — 19 commands..."
↓ ~185 tokens (constant)
Step 2: exec("search deploy") Vector search → top 5 matches
↓ ~50 tokens per result
Step 3: exec("describe git:push") Full definition + params
↓ ~100 tokens
Step 4: exec("git:push --branch main") Actual execution
↓ Structured JSON response
Step 5: exec("search backup database") Next task...
The LLM never sees all 19 commands. It discovers 2-3 at a time via semantic search.
| Namespace | Commands | Description |
|---|---|---|
| shell | exec, which |
Execute CLI commands, find binaries |
| file | read, write, list, exists, delete |
File operations |
| git | status, log, diff, branch, add, commit |
Git operations |
| http | get, post |
HTTP client |
| json | parse |
JSON parsing with dot-notation path extraction |
| env | get, list |
Environment variables |
| process | list |
Process management |
| Command | Description |
|---|---|
search <query> |
Semantic vector search for commands |
describe <name> |
Full definition + parameters |
list [namespace] |
List all or by namespace |
help |
Interaction protocol |
use PHPAgentShell\Command\CommandDefinition;
use PHPAgentShell\Command\CommandParam;
$shell->register(new CommandDefinition(
name: 'deploy:run',
description: 'Deploy the application to production',
params: [
new CommandParam('env', 'Target environment', 'string', true),
new CommandParam('dry-run', 'Simulate without executing', 'boolean', false, false),
],
namespace: 'deploy',
dangerous: true,
handler: function (array $args): array {
$env = $args['env'];
// ... deployment logic
return ['status' => 'deployed', 'environment' => $env, 'code' => 0];
},
));The LLM can now discover it: search "deploy to production" → deploy:run.
use PHPAgentShell\Integration\ShellToolkit;
class MyAgent extends \NeuronAI\Agent\Agent
{
protected function tools(): array
{
return [
new ShellToolkit($agentShell),
];
}
}Only 2 tools registered. The guidelines() method returns the protocol as system context.
use PHPAgentShell\Integration\ShellToolkit;
use PHPAgentMemory\Integration\Neuron\MemoryToolkit;
class FullAgent extends \NeuronAI\Agent\Agent
{
protected function tools(): array
{
return [
new ShellToolkit($shell), // 2 tools: help + exec
new MemoryToolkit($memory, ...), // 4 tools: save, recall, search, store_skill
];
}
}
// Total: 6 tools instead of 19+4 = 23 tools
// Tokens: ~400 instead of ~4,600Every exec() returns a structured response:
{
"code": 0,
"data": { "entries": [...], "count": 7 },
"error": null,
"meta": {
"command": "file:list --path /my/project",
"type": "exec",
"duration_ms": 1.1
}
}| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Error |
| 2 | Command not found |
| 124 | Timeout |
| 126 | Blocked (dangerous pattern) |
| 127 | Execution failed |
- Blocked commands:
rm -rf /,mkfs,dd if=, fork bombs — rejected before execution - Timeout: Default 30s, configurable per command via
--timeout - Dangerous flag: Commands marked
dangerous: trueare visible in search results so the LLM can make informed decisions - Argument escaping:
escapeshellarg()on user-provided values - Structured output: Commands return arrays, never raw shell output
use PHPAgentShell\AgentShell;
use PHPAgentShell\Executor\ShellExecutor;
$executor = new ShellExecutor(
defaultTimeout: 30, // seconds
workingDir: '/my/project', // default cwd
env: ['MY_VAR' => 'value'], // extra env vars
blockedCommands: ['rm -rf /'], // additional blocks
);
$shell = new AgentShell(
embedFn: fn(string $t) => embed($t),
dimensions: 768,
executor: $executor,
);PHPAgentShell needs an embedding function to index and search commands. Any provider works:
// Cloudflare (free)
$shell = new AgentShell(fn($t) => cfEmbed($t), 768);
// OpenAI
$shell = new AgentShell(fn($t) => openaiEmbed($t), 1536);
// Ollama (local)
$shell = new AgentShell(fn($t) => ollamaEmbed($t), 768);composer install
vendor/bin/phpunit # 26 tests, 59 assertions
# Demo with real embeddings (requires Cloudflare)
CF_ACCOUNT_ID=xxx CF_API_TOKEN=xxx php tests/demo-shell.php┌─────────────────────────────────────────────────────────┐
│ AgentShell │
│ help() + exec() │
├──────────┬──────────────────┬───────────────────────────┤
│ Parser │ CommandRegistry │ ShellExecutor │
│ │ + VectorSearch │ proc_open + timeout │
├──────────┴──────────────────┴───────────────────────────┤
│ 19 Built-in Skills │
│ shell · file · git · http · json · env · process │
├─────────────────────────────────────────────────────────┤
│ php-vector-store │
│ HybridSearch (BM25 + Vector RRF) │
└─────────────────────────────────────────────────────────┘
| Package | Purpose | Analogy |
|---|---|---|
| php-vector-store | Vector database | The storage engine |
| php-agent-memory | Agent memory + dream | The brain |
| php-agent-shell | CLI execution + discovery | The hands |
| Neuron AI | Agent framework | The body |
MIT