Remote API
The remote API lets an agent that cannot join your network talk to a chat
running on one of your machines. The motivating case is a cloud agent session:
it can reach the public hub over HTTPS, but not your VPN, so it cannot reach an
aya-helper directly. Your helpers already connect out to the hub, so the hub
is the meeting point. The agent sends a message to a chat, and reads the reply
back, through /api/remote/v1.
This is a separate surface from the browser UI, the worker protocol and the
service integrations. It has its own audience, its own two scopes, and its own
limits. The authoritative wire contract is
docs/api/remote-api.md and docs/api/openapi.json
(tag remote); this page is the integrator’s walkthrough.
Examples use hub.example.test for the hub and issuer.example.test for its
identity provider.
What a caller can do
- List the machines (a machine is the group of roots one helper serves), their roots and whether each is online.
- List projects, sessions and messages, and search.
- Send a message to an existing session, or start a new chat in a root.
- Read the reply by polling a turn’s events.
What it cannot do, by design:
- Ask for more than
allow-edits. The default isread-only;full-access,bypassPermissions,auto,planand provider-native modes are refused. - Choose a model tier, or see a local file path.
- Read a turn someone else queued.
Everything it sends is stamped, so the chat’s agent can tell it is talking to an external agent and not to you.
Get a token
HUB=https://hub.example.test
AUTH=$(curl -s "$HUB/api/remote/v1/auth-info")
ISSUER=$(echo "$AUTH" | jq -r .issuer)
RESOURCE=$(echo "$AUTH" | jq -r .resource)
TOKEN_ENDPOINT=$(curl -s "$ISSUER/.well-known/openid-configuration" | jq -r .token_endpoint)
TOKEN=$(curl -s -X POST "$TOKEN_ENDPOINT" \
-d grant_type=client_credentials \
-d client_id="$CLIENT_ID" \
-d client_secret="$CLIENT_SECRET" \
-d resource="$RESOURCE" \
-d scope="chat:read chat:drive" | jq -r .access_token)
Your operator registers the client in your identity provider and allows it to request this resource and these scopes. See Authentication for the scope table and the error bodies.
Send a message and read the reply
# Find a session (or machines/roots to start a new chat in).
curl -s -H "Authorization: Bearer $TOKEN" "$HUB/api/remote/v1/sessions?limit=5"
# Send. Reuse the same request_id to retry safely.
TURN=$(curl -s -X POST "$HUB/api/remote/v1/sessions/7/messages" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"request_id":"send-001","text":"Summarise the failing test."}' | jq -r .turn_id)
# Poll until done; each call holds up to 20 s waiting for something new.
SINCE=-1
while :; do
R=$(curl -s -H "Authorization: Bearer $TOKEN" \
"$HUB/api/remote/v1/turns/$TURN/events?since=$SINCE&wait_ms=20000")
echo "$R" | jq -c '.events[]'
SINCE=$(echo "$R" | jq -r .next_since)
[ "$(echo "$R" | jq -r .done)" = true ] && break
done
The repository ships a wrapper that does the token dance and the loop for you:
scripts/aya-remote.sh (machines, sessions, read, send, new,
wait), configured by AYA_HUB_URL, AYA_HUB_CLIENT_ID and
AYA_HUB_CLIENT_SECRET.
Things to know
- Retries are safe.
request_idis required on both writes. Repeating it with the same input returns the same turn (replayed: true); different input is a409. It is scoped to your client, so choose any unique string. - Turns can wait. If no helper has polled the chat’s root recently the
response carries a
warning. The turn is still queued, but a queued turn expires after ten minutes unclaimed, so check/machinesforonline. - Limits. Text is at most 64 KiB, a request body at most 256 KiB, and you
may have
REMOTE_MAX_ACTIVE_TURNS(default 8) turns waiting or running; past that you get429withRetry-After. - Re-claims. If a turn’s
claim_generationchanges between polls, a helper took it over; discard what you showed and read again fromsince=-1. - No ownership. The hub does not track who owns a session; a caller acts as the operator across everything the hub indexes. Treat a token for this resource as a credential to the operator’s chats, and grant it accordingly.
Run your own
The operator turns the surface on with REMOTE_API_RESOURCE and tunes it with
REMOTE_ALLOWED_SUBJECTS (required), REMOTE_MACHINE_ALIASES_JSON and
REMOTE_MAX_ACTIVE_TURNS; submits and reads are rate limited per subject
(429 with Retry-After). See Run your own.