{"id":51244589,"url":"https://github.com/agentruntimecontrolprotocol/php-sdk","last_synced_at":"2026-06-29T03:03:01.856Z","repository":{"id":356978807,"uuid":"1234794582","full_name":"agentruntimecontrolprotocol/php-sdk","owner":"agentruntimecontrolprotocol","description":"PHP reference SDK for ARCP (Agent Runtime Control Protocol).","archived":false,"fork":false,"pushed_at":"2026-06-23T13:21:04.000Z","size":1057,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-23T15:10:21.550Z","etag":null,"topics":["agent-protocol","agent-runtime-control-protocol","agents","ai-agents","arcp","durable-execution","llm","mcp","php","sdk","streaming"],"latest_commit_sha":null,"homepage":"https://github.com/agentruntimecontrolprotocol/spec","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agentruntimecontrolprotocol.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-10T16:45:26.000Z","updated_at":"2026-06-23T13:21:40.000Z","dependencies_parsed_at":null,"dependency_job_id":"2a3ced71-2cc2-4bdf-ac42-165d05fb07b1","html_url":"https://github.com/agentruntimecontrolprotocol/php-sdk","commit_stats":null,"previous_names":["agentruntimecontrolprotocol/php-sdk"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/agentruntimecontrolprotocol/php-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentruntimecontrolprotocol%2Fphp-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentruntimecontrolprotocol%2Fphp-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentruntimecontrolprotocol%2Fphp-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentruntimecontrolprotocol%2Fphp-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agentruntimecontrolprotocol","download_url":"https://codeload.github.com/agentruntimecontrolprotocol/php-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentruntimecontrolprotocol%2Fphp-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34911135,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-protocol","agent-runtime-control-protocol","agents","ai-agents","arcp","durable-execution","llm","mcp","php","sdk","streaming"],"created_at":"2026-06-29T03:03:01.197Z","updated_at":"2026-06-29T03:03:01.850Z","avatar_url":"https://github.com/agentruntimecontrolprotocol.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch3 align=\"center\"\u003eARCP PHP SDK\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\u003cstrong\u003ePHP SDK for the Agent Runtime Control Protocol (ARCP) — submit, observe, and control long-running agent jobs from PHP.\u003c/strong\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://packagist.org/packages/arcp/sdk\"\u003e\u003cimg alt=\"Packagist\" src=\"https://img.shields.io/packagist/v/arcp/sdk.svg\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/agentruntimecontrolprotocol/php-sdk/actions/workflows/test.yml\"\u003e\u003cimg alt=\"CI\" src=\"https://github.com/agentruntimecontrolprotocol/php-sdk/actions/workflows/test.yml/badge.svg\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://packagist.org/packages/arcp/sdk\"\u003e\u003cimg alt=\"PHP version\" src=\"https://img.shields.io/packagist/php-v/arcp/sdk.svg\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/agentruntimecontrolprotocol/spec/blob/main/docs/draft-arcp-1.1.md\"\u003e\u003cimg alt=\"ARCP\" src=\"https://img.shields.io/badge/ARCP-v1.1%20draft-blue\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg alt=\"License\" src=\"https://img.shields.io/badge/license-Apache--2.0-lightgrey\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/agentruntimecontrolprotocol/php-sdk\"\u003e\u003cimg alt=\"Codecov\" src=\"https://codecov.io/gh/agentruntimecontrolprotocol/php-sdk/branch/main/graph/badge.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/agentruntimecontrolprotocol/spec/blob/main/docs/draft-arcp-1.1.md\"\u003eSpecification\u003c/a\u003e ·\n  \u003ca href=\"#concepts\"\u003eConcepts\u003c/a\u003e ·\n  \u003ca href=\"#installation\"\u003eInstall\u003c/a\u003e ·\n  \u003ca href=\"#quick-start\"\u003eQuick start\u003c/a\u003e ·\n  \u003ca href=\"docs/\"\u003eGuides\u003c/a\u003e ·\n  \u003ca href=\"docs/\"\u003eAPI reference\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n`arcp/sdk` is the PHP reference implementation of [ARCP](https://github.com/agentruntimecontrolprotocol/spec/blob/main/docs/draft-arcp-1.1.md), the Agent Runtime Control Protocol. It covers both sides of the wire — `Arcp\\Client\\ARCPClient` for submitting and observing jobs, `Arcp\\Runtime\\ARCPRuntime` for hosting agents — so either side can talk to any conformant peer in any language without hand-rolling the envelope, sequencing, or lease enforcement.\n\nARCP itself is a transport-agnostic wire protocol for long-running AI agent jobs. It owns the parts of agent infrastructure that don't change between products — sessions, durable event streams, capability leases, budgets, resume — and stays out of the parts that do. ARCP wraps the agent function; it does not define how agents are built, how tools are exposed (that's MCP), or how telemetry is exported (that's OpenTelemetry).\n\n## Installation\n\nRequires PHP 8.4 or newer and Composer 2.x. The SDK ships as a single Composer package; the `bin/arcp` CLI is registered automatically so `vendor/bin/arcp` is available in any project that pulls it in.\n\n```sh\ncomposer require arcp/sdk\n```\n\nThe `pdo_sqlite`, `mbstring`, and `json` extensions are required (all bundled with most PHP distributions). The runtime uses [Amp v3](https://amphp.org/) + fibers; no extra extension is needed for async.\n\n## Quick start\n\nConnect to a runtime, submit a job, stream its events to completion:\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse Amp\\Websocket\\Client\\WebsocketHandshake;\nuse function Amp\\Websocket\\Client\\connect;\nuse Arcp\\Client\\ARCPClient;\nuse Arcp\\Envelope\\Envelope;\nuse Arcp\\Envelope\\MessageCatalog;\nuse Arcp\\Json\\EnvelopeSerializer;\nuse Arcp\\Messages\\Execution\\JobProgress;\nuse Arcp\\Messages\\Session\\Auth;\nuse Arcp\\Messages\\Session\\Capabilities;\nuse Arcp\\Messages\\Session\\PeerInfo;\nuse Arcp\\Transport\\WebSocketTransport;\n\n$serializer = new EnvelopeSerializer(MessageCatalog::create());\n$transport = new WebSocketTransport(\n    connect(new WebsocketHandshake('wss://runtime.example.com/arcp')),\n    $serializer,\n);\n\n$client = new ARCPClient($transport);\n$client-\u003eopen(\n    Auth::bearer((string) getenv('ARCP_TOKEN')),\n    new PeerInfo('quickstart', '1.0.0'),\n    new Capabilities(streaming: true, subscriptions: true),\n);\n\n$client-\u003esubscribe(\n    ['types' =\u003e ['job.progress', 'log', 'metric']],\n    static function (Envelope $env): void {\n        if ($env-\u003epayload instanceof JobProgress) {\n            printf(\"[progress %d%%] %s\\n\", $env-\u003epayload-\u003epercent, $env-\u003epayload-\u003emessage ?? '');\n        }\n    },\n);\n\n$result = $client-\u003einvokeTool('data-analyzer', ['dataset' =\u003e 's3://example/sales.csv']);\nprintf(\"final: %s\\n\", json_encode($result-\u003evalue));\n\n$client-\u003eclose();\n```\n\nThis is the whole shape of the SDK: open a session, submit work, consume an ordered event stream, get a terminal result or error. Everything below is detail on those four moves.\n\n## Concepts\n\nARCP organizes everything around four concerns — **identity**, **durability**, **authority**, and **observability** — expressed through five core objects:\n\n- **Session** — a connection between a client and a runtime. A session carries identity (a bearer token), negotiates a feature set in a `hello`/`welcome` handshake, and is *resumable*: if the transport drops, you reconnect with a resume token and the runtime replays buffered events. Jobs outlive the session that started them. See [§6](https://github.com/agentruntimecontrolprotocol/spec/blob/main/docs/draft-arcp-1.1.md).\n- **Job** — one unit of agent work submitted into a session. A job has an identity, an optional idempotency key, a resolved agent version, and a lifecycle that ends in exactly one terminal state: `success`, `error`, `cancelled`, or `timed_out`. See [§7](https://github.com/agentruntimecontrolprotocol/spec/blob/main/docs/draft-arcp-1.1.md).\n- **Event** — the ordered, session-scoped stream a job emits: logs, thoughts, tool calls and results, status, metrics, artifact references, progress, and streamed result chunks. Events carry strictly monotonic sequence numbers so the stream survives reconnects gap-free. See [§8](https://github.com/agentruntimecontrolprotocol/spec/blob/main/docs/draft-arcp-1.1.md).\n- **Lease** — the authority a job runs under, expressed as capability grants (`fs.read`, `fs.write`, `net.fetch`, `tool.call`, `agent.delegate`, `cost.budget`, `model.use`). The runtime enforces the lease at every operation boundary; a job can never act outside it. Leases may carry a budget and an expiry, and may be subset and handed to sub-agents via delegation. See [§9](https://github.com/agentruntimecontrolprotocol/spec/blob/main/docs/draft-arcp-1.1.md).\n- **Subscription** — read-only attachment to a job started elsewhere (e.g. a dashboard watching a job a CLI submitted). A subscriber observes the live event stream but cannot cancel or mutate the job. Distinct from *resume*, which continues the original session and carries cancel authority. See [§7.6](https://github.com/agentruntimecontrolprotocol/spec/blob/main/docs/draft-arcp-1.1.md).\n\nThe SDK models each of these as first-class objects; the rest of this README shows how.\n\n## Guides\n\n### Sessions and resume\n\nOpen a session, negotiate features, and reconnect transparently after a transport drop using the resume token — jobs keep running server-side while you're gone.\n\n```php\nuse Amp\\Websocket\\Client\\WebsocketHandshake;\nuse function Amp\\Websocket\\Client\\connect;\nuse Arcp\\Client\\ARCPClient;\nuse Arcp\\Envelope\\Envelope;\nuse Arcp\\Envelope\\MessageCatalog;\nuse Arcp\\Ids\\MessageId;\nuse Arcp\\Json\\EnvelopeSerializer;\nuse Arcp\\Messages\\Control\\Resume;\nuse Arcp\\Messages\\Session\\Auth;\nuse Arcp\\Messages\\Session\\Capabilities;\nuse Arcp\\Messages\\Session\\PeerInfo;\nuse Arcp\\Transport\\WebSocketTransport;\n\n$serializer = new EnvelopeSerializer(MessageCatalog::create());\n$openTransport = static fn (): WebSocketTransport =\u003e new WebSocketTransport(\n    connect(new WebsocketHandshake('wss://runtime.example.com/arcp')),\n    $serializer,\n);\n\n$client = new ARCPClient($openTransport());\n$accepted = $client-\u003eopen(\n    Auth::bearer((string) getenv('ARCP_TOKEN')),\n    new PeerInfo('resumable', '1.0.0'),\n    new Capabilities(streaming: true, durableJobs: true),\n);\n$sessionId = $accepted-\u003esessionId;\n$lastMessageId = null;\n\n// ... transport drops ...\n\n$resumed = new ARCPClient($openTransport());\n$resumed-\u003eopen(Auth::bearer((string) getenv('ARCP_TOKEN')), new PeerInfo('resumable', '1.0.0'), new Capabilities(streaming: true, durableJobs: true));\n$resumed-\u003esession-\u003etransport-\u003esend(new Envelope(\n    id: MessageId::random(),\n    payload: new Resume(afterMessageId: (string) $lastMessageId, includeOpenStreams: true),\n    timestamp: $resumed-\u003eclock-\u003enow(),\n    sessionId: $sessionId,\n));\n// The runtime replays every envelope with id \u003e $lastMessageId, then resumes live streaming.\n```\n\n### Submitting jobs\n\nSubmit a job with an agent (optionally version-pinned as `name@version`), an input, and an optional lease request, idempotency key, and runtime limit.\n\n```php\nuse Arcp\\Ids\\IdempotencyKey;\n\n$result = $client-\u003einvokeTool(\n    tool: 'weekly-report@2.1.0',\n    arguments: [\n        'week' =\u003e '2026-W19',\n        'lease' =\u003e ['net.fetch' =\u003e ['s3://reports/**']],\n        'expires_at' =\u003e (new DateTimeImmutable('+60 seconds'))-\u003eformat(DateTimeInterface::RFC3339_EXTENDED),\n    ],\n    deadlineSeconds: 300.0,\n    idempotencyKey: new IdempotencyKey('weekly-report-2026-W19'),\n);\n\nprintf(\"resolved value = %s\\n\", json_encode($result-\u003evalue));\n```\n\n### Consuming events\n\nIterate the ordered event stream — `log`, `metric`, `event.emit`, `tool.invoke`, `tool.result`, `job.progress`, `job.result_chunk`, `artifact.ref` — and optionally acknowledge progress so the runtime can release buffered events early.\n\n```php\nuse Arcp\\Envelope\\Envelope;\nuse Arcp\\Messages\\Execution\\JobProgress;\nuse Arcp\\Messages\\Execution\\ResultChunk;\nuse Arcp\\Messages\\Telemetry\\EventEmit;\nuse Arcp\\Messages\\Telemetry\\LogEvent;\nuse Arcp\\Messages\\Telemetry\\MetricEvent;\n\n$client-\u003esubscribe(\n    ['session_id' =\u003e [(string) $client-\u003esession-\u003esessionId]],\n    static function (Envelope $env) use ($client): void {\n        match (true) {\n            $env-\u003epayload instanceof LogEvent      =\u003e printf(\"[log] %s\\n\", $env-\u003epayload-\u003emessage),\n            $env-\u003epayload instanceof MetricEvent   =\u003e printf(\"[metric] %s=%s %s\\n\", $env-\u003epayload-\u003ename, $env-\u003epayload-\u003evalue, $env-\u003epayload-\u003eunit),\n            $env-\u003epayload instanceof JobProgress   =\u003e printf(\"[progress %d%%] %s\\n\", $env-\u003epayload-\u003epercent, $env-\u003epayload-\u003emessage ?? ''),\n            $env-\u003epayload instanceof ResultChunk   =\u003e $client-\u003eresultChunks-\u003epush($env-\u003epayload),\n            $env-\u003epayload instanceof EventEmit     =\u003e printf(\"[event] %s\\n\", $env-\u003epayload-\u003eeventType),\n            default                                =\u003e null,\n        };\n    },\n);\n```\n\n### Leases and budgets\n\nRequest capabilities, a budget, and an expiry; read budget-remaining metrics as they arrive; handle the runtime's enforcement decisions.\n\n```php\nuse Arcp\\Envelope\\Envelope;\nuse Arcp\\Errors\\BudgetExhaustedException;\nuse Arcp\\Messages\\Telemetry\\MetricEvent;\n\n$client-\u003esubscribe(\n    ['types' =\u003e ['metric']],\n    static function (Envelope $env): void {\n        if ($env-\u003epayload instanceof MetricEvent \u0026\u0026 $env-\u003epayload-\u003ename === 'cost.budget.remaining') {\n            printf(\"budget remaining: %.2f %s\\n\", $env-\u003epayload-\u003evalue, $env-\u003epayload-\u003eunit);\n        }\n    },\n);\n\ntry {\n    $client-\u003einvokeTool('web-research', [\n        'iterations' =\u003e 8,\n        'per_call_usd' =\u003e 0.30,\n        'lease' =\u003e [\n            'tool.call'   =\u003e ['search.*', 'fetch.*'],\n            'cost.budget' =\u003e ['USD:1.00'],\n            'model.use'   =\u003e ['anthropic/claude-*'],\n        ],\n        'expires_at' =\u003e (new DateTimeImmutable('+10 minutes'))-\u003eformat(DateTimeInterface::RFC3339_EXTENDED),\n    ]);\n} catch (BudgetExhaustedException $e) {\n    // BUDGET_EXHAUSTED / LEASE_EXPIRED are never retryable: resubmit with a fresh lease.\n    fwrite(STDERR, \"job ended: {$e-\u003ecode()-\u003evalue}\\n\");\n}\n```\n\n### Subscribing to jobs\n\nAttach read-only to a job submitted elsewhere and observe its live stream (with optional history replay) without cancel authority.\n\n```php\nuse Arcp\\Envelope\\Envelope;\n\n$listing = $observer-\u003elistJobs(['status' =\u003e ['running']], limit: 10);\n$first = $listing-\u003ejobs[0] ?? null;\nif ($first === null) {\n    return;\n}\n\n$subscriptionId = $observer-\u003esubscribe(\n    [\n        'job_id' =\u003e [$first['job_id']],\n        'since_message_id' =\u003e null,           // omit to start live; set for backfill\n    ],\n    static function (Envelope $env): void {\n        printf(\"[seq=%s] %s\\n\", (string) $env-\u003eid, $env-\u003etype());\n    },\n);\n\n// ... later ...\n$observer-\u003eunsubscribe($subscriptionId);\n```\n\n### Error handling\n\nCatch the typed error taxonomy and respect the `retryable` flag — `LEASE_EXPIRED` and `BUDGET_EXHAUSTED` are never retryable; a naive retry fails identically.\n\n```php\nuse Arcp\\Errors\\ARCPException;\nuse Arcp\\Errors\\BudgetExhaustedException;\nuse Arcp\\Errors\\ErrorCode;\nuse Arcp\\Errors\\LeaseExpiredException;\n\ntry {\n    $client-\u003einvokeTool('flaky');\n} catch (BudgetExhaustedException | LeaseExpiredException $e) {\n    throw $e; // resubmit with a fresh lease / budget instead\n} catch (ARCPException $e) {\n    if ($e-\u003eisRetryable()) {\n        // safe to retry with backoff (e.g. UNAVAILABLE, DEADLINE_EXCEEDED, INTERNAL)\n        return;\n    }\n    fprintf(STDERR, \"fatal: %s (%s)\\n\", $e-\u003ecode()-\u003evalue, $e-\u003egetMessage());\n    throw $e;\n}\n```\n\n## Feature support\n\nARCP features this SDK negotiates during the `hello`/`welcome` handshake:\n\n| Feature flag | Status |\n|---|---|\n| `heartbeat` | Supported |\n| `ack` | Partial |\n| `list_jobs` | Supported |\n| `subscribe` | Supported |\n| `lease_expires_at` | Supported |\n| `cost.budget` | Supported |\n| `model.use` | Supported |\n| `provisioned_credentials` | Supported |\n| `progress` | Supported |\n| `result_chunk` | Supported |\n| `agent_versions` | Supported |\n\n## Transport\n\nARCP is transport-agnostic. This SDK ships a WebSocket transport (default), an stdio transport for in-process child runtimes, and an in-memory transport for tests. WebSocket is the default for networked runtimes; stdio is used for in-process child runtimes. Select one by constructing the corresponding `Arcp\\Transport\\Transport` implementation (`new WebSocketTransport($connection, $serializer)`, `new StdioTransport(...)`, `MemoryTransport::pair()`) and passing it to `new ARCPClient($transport)`; the bundled `bin/arcp serve --host H --port P` exposes a WebSocket runtime that mirrors the same protocol on the wire.\n\n## API reference\n\nFull API reference — every type, method, and event payload — is in [`docs/`](docs/).\n\n## Versioning and compatibility\n\nThis SDK speaks **ARCP v1.1 (draft)**. The SDK follows semantic versioning independently of the protocol; the protocol version it negotiates is shown above and in `session.hello`. A runtime advertising a different ARCP MAJOR is not guaranteed compatible. Feature mismatches degrade gracefully: the effective feature set is the intersection of what the client and runtime advertise, and the SDK will not use a feature outside it.\n\n## Contributing\n\nSee [`CONTRIBUTING.md`](CONTRIBUTING.md). Protocol questions and proposed changes belong in the [spec repository](https://github.com/agentruntimecontrolprotocol/spec); SDK bugs and feature requests belong here.\n\n## License\n\nApache-2.0 — see [`LICENSE`](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagentruntimecontrolprotocol%2Fphp-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagentruntimecontrolprotocol%2Fphp-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagentruntimecontrolprotocol%2Fphp-sdk/lists"}