{"id":51244582,"url":"https://github.com/agentruntimecontrolprotocol/kotlin-sdk","last_synced_at":"2026-06-29T03:03:01.825Z","repository":{"id":356978815,"uuid":"1234794546","full_name":"agentruntimecontrolprotocol/kotlin-sdk","owner":"agentruntimecontrolprotocol","description":"Kotlin reference SDK for ARCP (Agent Runtime Control Protocol).","archived":false,"fork":false,"pushed_at":"2026-06-23T13:49:03.000Z","size":787,"stargazers_count":1,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-23T15:09:30.263Z","etag":null,"topics":["agent-protocol","agent-runtime-control-protocol","agents","ai-agents","arcp","durable-execution","jvm","kotlin","llm","mcp","sdk","streaming"],"latest_commit_sha":null,"homepage":"https://github.com/agentruntimecontrolprotocol/spec","language":"Kotlin","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:23.000Z","updated_at":"2026-06-23T13:45:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/agentruntimecontrolprotocol/kotlin-sdk","commit_stats":null,"previous_names":["agentruntimecontrolprotocol/kotlin-sdk"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/agentruntimecontrolprotocol/kotlin-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentruntimecontrolprotocol%2Fkotlin-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentruntimecontrolprotocol%2Fkotlin-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentruntimecontrolprotocol%2Fkotlin-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentruntimecontrolprotocol%2Fkotlin-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agentruntimecontrolprotocol","download_url":"https://codeload.github.com/agentruntimecontrolprotocol/kotlin-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentruntimecontrolprotocol%2Fkotlin-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","jvm","kotlin","llm","mcp","sdk","streaming"],"created_at":"2026-06-29T03:03:00.897Z","updated_at":"2026-06-29T03:03:01.814Z","avatar_url":"https://github.com/agentruntimecontrolprotocol.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch3 align=\"center\"\u003eARCP Kotlin SDK\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\u003cstrong\u003eKotlin SDK for the Agent Runtime Control Protocol (ARCP) — submit, observe, and control long-running agent jobs from Kotlin.\u003c/strong\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://central.sonatype.com/artifact/dev.arcp/arcp\"\u003e\u003cimg alt=\"Maven Central\" src=\"https://img.shields.io/maven-central/v/dev.arcp/arcp.svg\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/agentruntimecontrolprotocol/kotlin-sdk/actions/workflows/test.yml\"\u003e\u003cimg alt=\"CI\" src=\"https://github.com/agentruntimecontrolprotocol/kotlin-sdk/actions/workflows/test.yml/badge.svg\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/agentruntimecontrolprotocol/kotlin-sdk\"\u003e\u003cimg alt=\"codecov\" src=\"https://codecov.io/gh/agentruntimecontrolprotocol/kotlin-sdk/graph/badge.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\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/modules/arcp.md\"\u003eAPI reference\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n`dev.arcp:arcp` is the Kotlin 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 — `dev.arcp.client.ARCPClient` for submitting and observing jobs, `dev.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 JDK 21 or newer. The library is published to Maven Central as `dev.arcp:arcp` and pulls in its Kotlin coroutines, serialization, and datetime runtimes transitively. Add it with Gradle (Kotlin DSL):\n\n```kotlin\n// build.gradle.kts\ndependencies {\n    implementation(\"dev.arcp:arcp:1.1.0\")\n}\n```\n\nFor Maven users, the same coordinates apply (`groupId = dev.arcp`, `artifactId = arcp`, `version = 1.1.0`).\n\n## Quick start\n\nConnect to a runtime, submit a job, stream its events to completion:\n\n```kotlin\nimport dev.arcp.auth.StaticBearerAuth\nimport dev.arcp.client.ARCPClient\nimport dev.arcp.messages.Capabilities\nimport dev.arcp.messages.JobCompleted\nimport dev.arcp.messages.JobFailed\nimport dev.arcp.messages.JobSubmit\nimport dev.arcp.messages.SessionClose\nimport dev.arcp.runtime.ARCPRuntime\nimport dev.arcp.runtime.AgentRegistry\nimport dev.arcp.transport.MemoryTransport\nimport kotlinx.coroutines.flow.takeWhile\nimport kotlinx.coroutines.runBlocking\nimport kotlinx.serialization.json.buildJsonObject\nimport kotlinx.serialization.json.put\n\nfun main(): Unit = runBlocking {\n    // Paired in-memory transport: client end \u003c-\u003e runtime end.\n    val (clientTransport, runtimeTransport) = MemoryTransport.pair()\n    val agents = AgentRegistry().apply { register(\"data-analyzer\", \"1.0.0\", default = true) }\n    val runtime = ARCPRuntime(\n        supportedCapabilities = Capabilities(streaming = true),\n        agentRegistry = agents,\n        bearerAuth = StaticBearerAuth(mapOf(\"quickstart-token\" to \"quickstart\")),\n    )\n    runtime.accept(runtimeTransport)\n    ARCPClient(\n        transport = clientTransport,\n        auth = ARCPClient.bearer(\"quickstart-token\"),\n        client = ARCPClient.defaultClientInfo(principal = \"quickstart\"),\n        capabilities = Capabilities(streaming = true),\n    ).use { client -\u003e\n        val session = client.open()\n        client.send(session.sessionId, JobSubmit(\n            agent = \"data-analyzer\",\n            input = buildJsonObject { put(\"dataset\", \"s3://example/sales.csv\") },\n        ))\n        client.receive().takeWhile { env -\u003e\n            when (val p = env.payload) {\n                is JobCompleted -\u003e { println(\"final: ${p.result}\"); false }\n                is JobFailed -\u003e { println(\"error: ${p.code} ${p.message}\"); false }\n                else -\u003e { println(\"[${env.type}] ${env.payload}\"); true }\n            }\n        }.collect {}\n        client.send(session.sessionId, SessionClose())\n    }\n    runtime.close()\n}\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```kotlin\nimport dev.arcp.client.ARCPClient\nimport dev.arcp.messages.Capabilities\nimport dev.arcp.transport.MemoryTransport\n\nval (clientTransport, _) = MemoryTransport.pair()\nARCPClient(\n    transport = clientTransport,\n    auth = ARCPClient.bearer(System.getenv(\"ARCP_TOKEN\")),\n    client = ARCPClient.defaultClientInfo(principal = \"resumable\"),\n    capabilities = Capabilities(\n        streaming = true,\n        heartbeatIntervalSeconds = 30,\n    ),\n).use { client -\u003e\n    val session = client.open()                 // four-message handshake (RFC §8.1)\n    println(\"session id: ${session.sessionId}\")\n    println(\"negotiated caps: ${session.capabilities}\")\n    println(\"lease expires: ${session.lease?.expiresAt}\")\n    // The runtime tracks `last_event_seq` for this session in its EventLog; on a\n    // transport drop, opening a new ARCPClient and replaying events from the\n    // recorded sequence number is the resume path.\n}\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```kotlin\nimport dev.arcp.messages.JobSubmit\nimport kotlinx.serialization.json.buildJsonArray\nimport kotlinx.serialization.json.buildJsonObject\nimport kotlinx.serialization.json.put\n\nval requestId = client.send(\n    session.sessionId,\n    JobSubmit(\n        agent = \"weekly-report@2.1.0\",\n        input = buildJsonObject { put(\"week\", \"2026-W19\") },\n        leaseRequest = buildJsonObject {\n            put(\"net.fetch\", buildJsonArray { add(\"s3://reports/**\") })\n        },\n        leaseConstraints = buildJsonObject {\n            put(\"expires_at\", \"2026-05-22T12:00:00Z\")\n        },\n        idempotencyKey = \"weekly-report-2026-W19\",\n        maxRuntimeSec = 300,\n    ),\n)\nprintln(\"submitted: $requestId — await job.accepted with this correlationId\")\n```\n\n### Consuming events\n\nIterate the ordered event stream — `log`, `thought`, `tool_call`, `tool_result`, `status`, `metric`, `artifact_ref`, `progress`, `result_chunk` — and optionally acknowledge progress so the runtime can release buffered events early.\n\n```kotlin\nimport dev.arcp.client.ResultChunkAssembler\nimport dev.arcp.messages.JobCompleted\nimport dev.arcp.messages.JobFailed\nimport dev.arcp.messages.JobProgress\nimport dev.arcp.messages.JobResultChunk\nimport dev.arcp.messages.JobStatusEvent\nimport dev.arcp.messages.Metric\nimport kotlinx.coroutines.flow.takeWhile\n\nval chunks = ResultChunkAssembler()\nclient.receive().takeWhile { env -\u003e\n    when (val p = env.payload) {\n        is JobStatusEvent  -\u003e { println(\"status: ${p.phase} ${p.body}\"); true }\n        is JobProgress     -\u003e { println(\"progress: ${p.percent}% ${p.message}\"); true }\n        is Metric          -\u003e { println(\"metric: ${p.name}=${p.value} ${p.unit}\"); true }\n        is JobResultChunk  -\u003e { chunks.accept(p); true }\n        is JobCompleted    -\u003e { println(\"result: ${p.result}\"); false }\n        is JobFailed       -\u003e { println(\"failed: ${p.code} ${p.message}\"); false }\n        else               -\u003e true\n    }\n}.collect {}\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```kotlin\nimport dev.arcp.error.ARCPException\nimport dev.arcp.lease.BudgetAmount\nimport dev.arcp.lease.CostBudget\nimport dev.arcp.lease.Currency\nimport dev.arcp.messages.JobSubmit\nimport dev.arcp.messages.Metric\nimport dev.arcp.messages.StandardMetrics\nimport kotlinx.serialization.json.buildJsonArray\nimport kotlinx.serialization.json.buildJsonObject\nimport kotlinx.serialization.json.put\nimport java.math.BigDecimal\n\nval budget = CostBudget(listOf(BudgetAmount(Currency(\"USD\"), BigDecimal(\"1.00\"))))\n\nclient.send(\n    session.sessionId,\n    JobSubmit(\n        agent = \"web-research\",\n        input = buildJsonObject { put(\"iterations\", 8) },\n        leaseRequest = buildJsonObject {\n            put(\"tool.call\", buildJsonArray { add(\"search.*\"); add(\"fetch.*\") })\n            put(\"cost.budget\", buildJsonArray {\n                budget.budgets.forEach { add(it.render()) }\n            })\n        },\n        leaseConstraints = buildJsonObject {\n            put(\"expires_at\", \"2026-05-22T13:00:00Z\")\n        },\n    ),\n)\n\ntry {\n    client.receive().collect { env -\u003e\n        val m = env.payload as? Metric ?: return@collect\n        if (m.name == StandardMetrics.COST_BUDGET_REMAINING) {\n            println(\"budget remaining: ${m.value} ${m.unit}\")\n        }\n    }\n} catch (e: ARCPException.BudgetExhausted) {\n    // Never retryable — request a fresh budget on a new submit instead.\n    println(\"budget exhausted for ${e.currency}\")\n}\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```kotlin\nimport dev.arcp.error.ARCPException\nimport dev.arcp.error.ErrorCode\n\ntry {\n    val session = client.open()\n    // ... submit, collect events ...\n} catch (e: ARCPException) {\n    when (e.code) {\n        ErrorCode.LEASE_EXPIRED,\n        ErrorCode.BUDGET_EXHAUSTED -\u003e throw e   // resubmit with fresh lease / budget\n        ErrorCode.UNAUTHENTICATED -\u003e throw e   // refresh credentials, then reopen\n        else -\u003e if (e.retryable) {\n            // safe to retry with backoff (e.g. UNAVAILABLE, INTERNAL)\n        } else {\n            throw e\n        }\n    }\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` | Catalog only — runtime returns `UNIMPLEMENTED` Nack on `subscribe`-style ack envelopes |\n| `list_jobs` | Supported |\n| `subscribe` | Catalog + helpers; runtime does **not** dispatch `subscribe`/`unsubscribe` yet |\n| `lease_expires_at` | Supported |\n| `cost.budget` | Supported |\n| `model.use` | Catalog + helpers; runtime does not yet enforce per-call model use |\n| `provisioned_credentials` | Supported |\n| `progress` | Supported |\n| `result_chunk` | Client-side assembly only; runtime does not emit chunks itself |\n| `agent_versions` | Supported |\n\nSee [`docs/conformance.md`](docs/conformance.md) for a per-section\nbreakdown of which message types are routed by `ARCPRuntime.handleEnvelope`\nversus types that exist only in the catalog. The session\nchallenge/authenticate flow, delegation, artifacts dispatch, resume, and\ninterrupt are all in the catalog but deferred from runtime dispatch — a\npeer that sends them today receives a correlated `UNIMPLEMENTED` Nack.\n\n## Transport\n\nARCP is transport-agnostic. This SDK ships an in-memory transport (`MemoryTransport`) used by the integration test suite and for in-process embedding of a runtime; the WebSocket and stdio transports defined in the spec are planned and not yet on the public API surface. Construct one with `MemoryTransport.pair()` for a connected (client, runtime) pair, and pass the appropriate end into the `ARCPClient(transport = ...)` or `ARCPRuntime.accept(transport)` call.\n\n## API reference\n\nFull API reference — every type, method, and event payload — is in [`docs/`](docs/) and as Dokka-generated module pages under [`docs/modules/`](docs/modules/).\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%2Fkotlin-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagentruntimecontrolprotocol%2Fkotlin-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagentruntimecontrolprotocol%2Fkotlin-sdk/lists"}