Skip to content

Cortex relay

Cortex is the fallback for brains that can’t accept inbound connections: serverless functions, a process on a laptop behind NAT, or a network that only allows egress. Instead of the runtime dialing you, your brain dials out to a Cortex relay, which splices the two legs together.

Cortex is a stateless, schema-free WebSocket relay with exactly two routes:

  • The voice runtime lands on /?session_id={session_id}.
  • Your brain dials out to /agent.

Both legs authenticate to the same tenant-and-agent rendezvous scope, and Cortex matches them on that — derived from the credentials, not from the URL. There is nothing to encode in a path and nothing to configure. Cortex holds no state. Many sessions multiplex over your one outbound socket, demuxed by a 16-byte session prefix.

Self-service, over the MCP server:

create_agent_credentials(tenant, agent_id, label="")

It returns three things you use in three different places:

FieldWhere it goes
agent_secretsk_… — the SDK’s api_key=. The same kind create_agent gave you; shown once, never recoverable.
cortex_urlThe SDK’s cortex_url=. It already ends in /agent — pass it verbatim; the SDK does not append.
brain_urlThe Cortex origin. This is what the agent’s brain_url must become.

Wiring the brain_url is not automatic:

update_agent(tenant, agent_id, brain_url="<the brain_url it returned>")

Until you do, the agent still points wherever it pointed before. Keys never expire, and minting revokes nothing, so rotation is mint → redeploy → revoke_api_key on the old one, with no window where the agent can’t connect.

The same Brain class runs over Cortex; only the entrypoint changes.

from voqalize.sdk import serve
from mybrain import MyBrain
await serve(
MyBrain, # or a () -> Brain callable, if the brain takes dependencies
version="1.0.0",
cortex_url="wss://cortex.dev.voqalize.com/agent", # verbatim, from the tool
api_key="sk_…", # OR authorization_provider=lambda: "Bearer <jwt>"
) # returns when the wire closes permanently

Pass exactly one credential: a static api_key (sk_…), or an authorization_provider that mints a "Bearer <jwt>" per connect.

serve blocks for the life of the relay connection. Where that call lives — asyncio.run in a __main__, a task in your app’s lifespan, a worker entrypoint — is yours to decide; the SDK owns no process management.

Because the brain dials out, Cortex needs no public inbound route and no tunnel — which is why it fits serverless and egress-only environments, and why it is the fastest way to develop against hosted Voqalize from a laptop. Export the credentials and run:

Terminal window
export VOQAL_AGENT_SECRET=sk_... # agent_secret
export VOQAL_CORTEX_URL=wss://cortex.dev.voqalize.com/agent # cortex_url, verbatim
python run_cortex.py

Both are conventions your own code reads and passes through as the kwargs above — the SDK reads no environment variables of its own.

Cortex keeps no session state — that lives in the endpoints (the runtime’s session and your brain). There’s no drain protocol and no graceful-shutdown contract. Your agent leg reconnects and carries on; the calls that were in flight when it died do not survive, because a voice session is its socket.