PHP 8.4 reference implementation of the Agent Runtime Control Protocol (ARCP) v1.0.
Status: v0.1 complete. The Phase 0 plan is in PLAN.md; the conformance matrix is in CONFORMANCE.md.
composer install
# Tests
vendor/bin/phpunit --testdox
# Static analysis
vendor/bin/phpstan analyze
vendor/bin/psalm --no-cache
# Formatter
vendor/bin/php-cs-fixer fix --dry-run --diff
# Run a sample
php samples/02_tool_invoke_with_progress.php
# Run a runtime exposing a websocket port
bin/arcp serve --host 127.0.0.1 --port 8765- PHP 8.4 or newer.
- Composer 2.x.
- The
pdo_sqlite,mbstring, andjsonextensions (bundled with most PHP distributions).
+-----------------------------+
| Capability Layer |
| (MCP Compatible) |
+-----------------------------+
+-----------------------------+
| ARCP Runtime Layer |
| - Identity & Sessions |
| - Streams |
| - Jobs |
| - Subscriptions |
| - Events |
| - Permissions & Leases |
| - Artifacts |
| - Tracing & Metrics |
+-----------------------------+
+-----------------------------+
| Transport Layer |
| WebSocket / stdio (mandatory)|
+-----------------------------+
The runtime is Arcp\Runtime\ARCPRuntime; the client is
Arcp\Client\ARCPClient. Both are async (Amp v3 + fibers) and both take a
Arcp\Transport\Transport instance, which is one of MemoryTransport,
WebSocketTransport, or StdioTransport.
use Arcp\Auth\AuthRouter;
use Arcp\Auth\NoneAuth;
use Arcp\Client\ARCPClient;
use Arcp\Messages\Session\Auth;
use Arcp\Messages\Session\Capabilities;
use Arcp\Messages\Session\PeerInfo;
use Arcp\Runtime\ARCPRuntime;
use Arcp\Runtime\JobContext;
use Arcp\Runtime\ToolHandler;
use Arcp\Transport\MemoryTransport;
$runtime = new ARCPRuntime(authRouter: new AuthRouter([new NoneAuth()]));
$runtime->registerTool('echo', new class implements ToolHandler {
public function invoke(array $args, JobContext $ctx, ?\Amp\Cancellation $c = null): mixed
{
return ['echoed' => $args];
}
});
[$serverT, $clientT] = MemoryTransport::pair();
$serverFuture = $runtime->serveAsync($serverT);
$client = new ARCPClient($clientT);
$client->open(
Auth::none(),
new PeerInfo('demo', '0.1'),
new Capabilities(anonymous: true),
);
$result = $client->invokeTool('echo', ['ping' => 'pong']);
print_r($result->value);
$client->close();
$serverFuture->await();bin/arcp (registered in composer.json's bin):
| Command | Purpose |
|---|---|
arcp serve --host H --port P |
Run a runtime accepting WebSocket connections. |
arcp tail ws://host:port/ |
Subscribe and print every envelope. |
arcp send ws://… <tool> -a '{"k":"v"}' |
Invoke a tool and print the result. |
arcp replay events.sqlite -a msg_xyz |
Replay an event log file. |
| RFC section | Implementation |
|---|---|
| §6.1 Envelope | src/Envelope/Envelope.php |
| §6.2 Message types | src/Messages/ + src/Envelope/MessageCatalog.php |
| §7 Capability negotiation | src/Runtime/ARCPRuntime.php |
| §8 Authentication | src/Auth/ |
| §10 Jobs | src/Runtime/JobManager.php + JobContext |
| §11 Streaming | JobContext::openStream() (text/event/log/thought; binary base64 only) |
| §12 Human-in-the-loop | src/Client/Handlers/ + JobContext::requestHumanInput/Choice |
| §13 Subscriptions | src/Runtime/SubscriptionManager.php |
| §15 Permissions & leases | src/Runtime/LeaseManager.php |
| §16 Artifacts | src/Runtime/ArtifactStore.php |
| §17 Observability | src/Messages/Telemetry/ |
| §18 Errors | src/Errors/ |
| §19 Resume | src/Store/EventLog.php |
| §21 Extensions | src/Extensions/ |
| §22 Transports | src/Transport/ |
Six runnable scripts under samples/, each backed by a
single sentence of context at the top. They all use MemoryTransport
to keep the example self-contained:
01_minimal_session.php— handshake.02_tool_invoke_with_progress.php— tool + progress events.03_human_input_request.php— HITL input.04_permission_challenge.php— permission/lease.05_observer_subscription.php— passive observer.06_relay_human_in_the_loop.php— multi-channel HITL relay.
See PLAN.md §7 for the full
list. Calls into out-of-scope surfaces throw UnimplementedException
with the relevant RFC section.
Apache-2.0.