Skip to content

Bring your own (A2A)

Bring an LLM agent you already run: any A2A agent on your own infrastructure, in any language or framework. The platform stores only the URL of its Agent Card and reads the card each time it calls the agent. Apart from that, it behaves like an LLM agent created in ROC: it appears in ROC, a vault owner connects it, a workflow’s Agent step can call it, and its answers land in the vault as events.

Use one when the agent already exists as a service, needs runtimes or dependencies the platform does not offer, or belongs to another team. Create an LLM agent in ROC when instructions and a model are enough, and write a code agent when the logic is yours to run on the platform.

The platform’s own name for an agent hosted elsewhere is external: the CLI registers it with --kind external, and ROC’s Fleet dashboard and Sandbox switcher mark it with an External badge.

Register it

Terminal window
cef push --kind external \
--card https://agent.example.com \
--bucket <bucketId> \
--as-pubkey <agentServicePubkey>

cef push fetches the card and checks that it declares an endpoint. It then writes a manifest for the agent into your Agent Service’s bucket. No code is built or uploaded.

Flag Default Meaning
--card <url> required The Agent Card URL. If you give a bare origin, /.well-known/agent-card.json is appended.
--bucket <id> required The Agent Service’s DDC bucket.
--as-pubkey <hex> none The Agent Service pubkey, which forms the agent id <pubkey>:<alias>. Without it the manifest has no agent id, and you have to push again with it.
--alias <name> slug of the card’s name The registry alias. It must not contain :.
--agent-version <semver> 1.0.0 The version to register.
--scope <name...> default The vault scopes the agent asks for. The vault owner still grants them when they connect.
--idle-timeout <duration> 30m How long a conversation survives with no events. 0 is refused.

Credentials and environment flags (--secret-phrase, --access-token, --subject-phrase, --env, --preset, --endpoint, --cdn) work as they do for a code agent. See the CLI reference.

Flags that only apply to a code agent (--agent, --out, --vault, --vault-scope, --vault-api, --vault-token) are refused with --kind external, and --card is refused without it.

You can also register one in ROC: open Agents, click Import agent, and fill in Card URL or Bridge name, Registry name, and Description. In the Agents list its row reads runs elsewhere.

What the card must declare

Card field Used for
An interface with a JSON-RPC binding (supportedInterfaces[].protocolBinding: "JSONRPC" or 0.3’s interfaces[].transport), or a top-level url Where the platform sends calls. A card that declares no endpoint is refused at push.
name, description The default alias and the listing shown in ROC.
securitySchemes / security Decides which credential the platform sends. See Authentication.

The card is read again every time the platform calls the agent, so you can change endpoints and skills without pushing again.

How the platform calls it

  • Transport: JSON-RPC 2.0 over HTTP POST to the card’s endpoint. The methods are SendMessage and GetTask. If your server answers -32601, the platform retries once with message/send and tasks/get.
  • No streaming: the platform sends the message with returnImmediately: true and then polls GetTask until the task reaches a final state. A turn times out after 15 minutes.
  • Message: the first non-empty value among the event payload’s text, message, prompt, question, and body becomes a text part. The rest of the payload becomes a data part.
  • Metadata: each message carries vaultId, jobId, taskId, scope, context, engagement, eventType, and onBehalfOf. onBehalfOf is the public key of the person whose event started the turn; it is empty for schedules and for events from other agents.

Context and Jobs

One Job is one A2A contextId. The first turn sends no contextId. The platform stores the one your agent returns and sends it on every later turn in that Job. Each turn is a new A2A task.

The Job ends after --idle-timeout with no events. The next event then starts a new Job with a new context, so your agent sees it as a new conversation. Set the timeout to cover the human gaps in your flow: a person reading, or a reply to a question your agent asked.

State mapping

Your task state What happens
TASK_STATE_COMPLETED The turn succeeds and the platform publishes agent.answered.
TASK_STATE_INPUT_REQUIRED, TASK_STATE_AUTH_REQUIRED The turn ends and agent.answered is published with payload.state set to that state. The person’s reply arrives as the next event, which starts a new task in the same context.
TASK_STATE_FAILED, TASK_STATE_CANCELED, TASK_STATE_REJECTED The turn fails and is retried. When retries run out, the platform publishes agent.answered with payload.error and payload.code.
TASK_STATE_SUBMITTED, TASK_STATE_WORKING The platform keeps polling. On timeout, the retry rejoins the same remote task instead of sending the message again.

A reply that is a bare Message rather than a Task counts as completed.

How answers reach the vault

The platform publishes your answer into the vault on your agent’s behalf:

Event When Payload
agent.answered After every turn, including failures agentId, agent (alias), text, a2aTaskId, state, jobId, taskId; plus data (structured parts), usage, conversation, and actions when present; error and code on failure
agent.progress While a turn runs Progress steps

The answer’s parents is the event that asked. If the asking event carried metadata.correlation, the answer echoes it back unchanged. This is how a workflow Agent step matches your answer to the step that asked.

Answering a workflow step

A workflow agent step publishes an event targeted at your agent (target: <asPubkey>:<alias>). Events reach an agent registered this way only when they are targeted at it; untargeted events in the scope are not delivered. Your reply becomes agent.answered, and the step reads it. Return the fields the step needs in a data part, which arrives as payload.data.

Authentication

If your card lists oauth2, openIdConnect, or an http bearer scheme with bearerFormat: "JWT" as a required security scheme, the platform sends Authorization: Bearer <execution token>. The execution token is a JWT signed by the Agent Service’s key. It names the vault, scope, agent, Job, and task, and the person the turn is on behalf of. Verify it before you act. If the platform cannot mint the token, the call fails; it never falls back to an unauthenticated call.

Spend ceilings

A vault owner can cap an agent registered this way with an a2aTokens ceiling on the connection. The platform counts the token usage your agent reports and refuses new turns once the count passes the ceiling. See Connect to a vault.