Endpoints
The control plane and harness use separate sockets for turns, queries, operations, and execution. Each route requires the credentials listed below.
The control plane serves the turn, read, and operations routes. It owns the public API, reconciler, and approval checks, and commits turn records through the state plane. The state plane alone writes the durable event log. A harness runs the agent loop in an isolated pod and serves the execution route. config.rs sets the default addresses. An environment variable overrides each address.
The four sockets
Edges call the turn socket, and the web app calls the read socket. Cluster probes call the operations socket; the control plane calls the harness. The cluster does not expose the harness to external callers. A mobile client's backend acts as its edge, holding credentials and translating requests to the public API.
| Socket | Default address | Set by | Bound when |
|---|---|---|---|
| Turn | [::]:8080 | POLYCHROME_GRPC_ADDR | Always |
| Operations | [::]:8081 | POLYCHROME_SIDE_ADDR | Always |
| Read | Unset. The manifests set [::]:8090. | POLYCHROME_FORENSICS_ADDR | Only when you set the address |
| Harness | :50053 | The reconciler, per conversation | One socket per running conversation |
The WhatsApp edge receives Meta's GET verification and signed POST deliveries at /whatsapp/webhook on its own listener (default :8102). It then calls the control plane's turn socket using edge credentials. Its health and metrics listener defaults to :8101. See WhatsApp for authentication and delivery limits.
The turn socket
The turn socket runs every turn. It speaks gRPC and the HTTP/JSON Connect protocol from one registration. A generated client and a curl command reach the same handler. The chat-completions route is a translation in front of that same handler. An edge presents an edge credential and a signed envelope. The signature binds each turn to the edge that sends it.
- RPCstream
/polychrome.agent.v1.AgentService/ConnectEdge credentialRuns one turn. Streams the outputs until the turn ends or pauses.
- RPC
/polychrome.agent.v1.AgentService/ClassifyEdge credentialDecides whether a message needs a turn.
- RPC
/polychrome.agent.v1.AgentService/InterruptEdge credentialCancels a turn that already runs.
- RPC
/polychrome.approval.v1.ApprovalService/RespondEdge credentialResolve tokenAnswers a paused approval. Signs the answer and records the approver.
- RPC
/polychrome.question.v1.QuestionService/RespondEdge credentialAnswers a question that the agent stops to ask.
- RPC
/polychrome.persona.v1.PersonaService/*Edge credentialLinks, describes, and administers personas. Admin RPCs also need an admin persona.
- RPC
/polychrome.credential.v1.CredentialService/*Admin credentialEnrolls, rotates, and revokes edge credentials while the process runs.
- RPCstream
/polychrome.ops.v1.NotificationService/SubscribeEdge credentialStreams pending decisions to an edge. The edge shows each one to a person.
- POSTstream
/v1/chat/completionsEdge credentialRuns a turn under the chat-completions schema. Streams the reply as SSE.
- RPC
/grpc.health.v1.Health/CheckNo credentialReports the serving state of the process and of AgentService.
An unmounted route returns 404. The control plane omits a service when a required authorization dependency is absent, such as persona hosting or credential storage.
The compatibility route
Compatible clients can send turns to this route with an edge credential and the required headers. The control plane stores conversation history and reconstructs it from the event log. The route forwards only messages after the last assistant reply as the new turn.
Put the conversation id in the X-Polychrome-Conversation header. You can use the conversation body field instead. Omit the id, and the server creates a web:{owner}.{random} id scoped to your credential. The server returns that id in the same response header.
curl -N http://polychrome-control-plane:8080/v1/chat/completions \
-H 'authorization: Bearer pc_<edge-id>_<secret>' \
-H 'content-type: application/json' \
-H 'idempotency-key: <at least 8 bytes, unique per attempt>' \
-d '{"model":"polychrome","stream":true,
"messages":[{"role":"user","content":"summarize today's incidents"}]}'The response schema includes two extensions. A turn that stops for a person ends with finish_reason: "tool_calls". It also carries a polychrome object that names the pending approval. A handoff to another agent appears in that same object. A client that ignores the object sees an ordinary completion. The module docs state the full subset that the route reads.
The read socket
The read socket serves transcripts and usage totals derived from signed event-log entries. The control plane binds this socket only when you set its address. Its browser routes require a session credential.
The routes enforce administrator, participant, or self access. Query scope remains limited by the caller's permissions.
- AdminEvery conversation, every persona, and deployment-wide usage totalsA session whose persona is an admin
- ParticipantOne conversation's transcript, approvals, and traceA session named on that conversation. An admin also qualifies.
- SelfYour own conversations and your own profileAny valid session
- RPC
/polychrome.web_auth.v1.WebAuthService/ExplorerAuthChallengeOpen ceremonyStarts passkey authentication.
- RPC
/polychrome.web_auth.v1.WebAuthService/WalletAuthVerifyOpen ceremonyVerifies wallet authentication and sets the session cookie.
- GET
/api/me/conversationsSelfLists every conversation that the caller takes part in.
- GET
/api/conversations/{id}/transcriptParticipantReplays one conversation's messages from the event log.
- GET
/api/conversations/{id}/approvalsParticipantLists every approval the conversation asks for. Shows the answer to each one.
- RPCstream
/polychrome.forensics.v1.ForensicsService/GetTraceStreamParticipantFollows a running conversation. Sends an event each time the trace changes.
- POST
/api/querySelfRuns one bounded query. The caller's permissions limit which records it reads.
- POST
/api/chat/turnSession with turn scopeDispatches a turn from the browser into one of the caller's conversations.
- GET
/api/conversationsAdminLists conversations across the deployment.
- GET
/api/usageAdminTotals token usage across the deployment. Filters by persona and by time.
- POST
/admin/modelAdmin credentialChanges the live model selection.
An unmatched path on this socket returns 401 rather than 404. This avoids confirming whether a guessed route exists. Protected responses carry no-store whether the request succeeds or fails authorization. The route table shows each route's authorization check.
The operations socket
The operations socket exposes process health and metrics without conversation data or credentials. A separate port lets the cluster's network policy restrict access to probes.
- GET
/healthzNo credentialAnswers 200 after the process starts.
- GET
/livezNo credentialAnswers 200 while the process runs.
- GET
/readyzNo credentialAnswers 200 only after every bound socket serves.
- GET
/metricsNo credentialPublishes the process's counters and histograms for a scraper.
- POST
/drainNo credentialFails readiness. Traffic drains before shutdown.
Kubernetes probes readiness on the turn socket, not here. The operations socket can start serving before the turn socket is available. Kubernetes therefore uses the native gRPC health check on :8080. /drain flips that check to NOT_SERVING. See health.rs.
The harness socket
In per-conversation mode, each running conversation has a harness pod. The control plane connects after the reconciler attaches the sandbox. Network policy limits access to the control plane. The harness has no Kubernetes token and cannot call the Kubernetes API.
- RPCstream
/polychrome.harness.v1.HarnessService/ConnectThe control plane onlyReceives turn inputs from the control plane and streams outputs and tool calls back.
What you can reach from outside
The supplied cluster deployment keeps these sockets private. External turn requests pass through an edge that authenticates its callers before dispatch.
| Host | What answers | How it reaches a turn |
|---|---|---|
polychrome.sh | The web app | It proxies to the read socket and the turn socket. A browser session authorizes each call. |
mcp.polychrome.sh/mcp | The repository MCP server | Provides repository tools; it does not dispatch conversation turns. |
docs.polychrome.sh | This site | Static documentation; no turn dispatch. |
See Edges for the adapter contract and Trust for approval requirements.