Spec popisuje motivaci extrakce, kontrakt mezi control-plane (TalkIDE BE) a workerem, komunikační protokol (HTTP + SSE), strategii session resume na NFS a otevřené body. Cílem není opakovat ADR-024 — cílem je rozkrýt operativní detaily, které jsou potřeba pro implementaci a runbooky.
1. Motivace (zkrácená)
Plný argument viz ADR-024 § Context. V kostce:
- In-process sidecar (
AgentSidecarExecutor) multiplexoval všechny konverzace všech tenantů jednou NDJSON pipe v jediném BE podu → škálovací zeď + OOM + JVM warmup interference. - Sidecar životnost = BE životnost → každý BE redeploy přerušil 3-week Mara resume.
- Gradle build/test v dev-loopu žil ve stejném JVM/podu → další zdroj OOM.
Cílový stav (LIVE):
- Node/TypeScript worker pod per
tenant-environmentnamespace ({tenant}-{env}, viz ADR-026). - Worker volá Anthropic Agent SDK in-process — žádný child Node proces, žádná stdin/stdout pipe.
- Worker volá Anthropic API přes platform gateway-proxy v control-plane (TalkIDE BE) — worker
nikdy nedrží raw
ANTHROPIC_API_KEY. - Gradle build/test = ephemeral K8s Joby dispatchnuté workerem (rozšíření Kaniko Job patternu, ADR-019).
- Session state (CLAUDE_CONFIG_DIR transcript) na NFS PVC (talkide-infra
claude-sessions), worker pod survives BE redeploy a re-startuje sám.
2. Architektura — high level
flowchart TB
subgraph CP[control-plane namespace 'talkide-prod']
BE[TalkIDE BE<br/>Spring Boot]
GW[Gateway-proxy<br/>endpoint /api/internal/gateway/anthropic/*<br/>holds ANTHROPIC_API_KEY]
BE --- GW
end
subgraph TE[tenant-env namespace e.g. 'mirek-dev']
WORKER[talkide-worker pod<br/>Node 22+ TS<br/>Anthropic Agent SDK in-process]
NFS[NFS PVC<br/>claude-sessions<br/>CLAUDE_CONFIG_DIR]
WORKER -.- NFS
end
subgraph BUILDS[ephemeral Jobs in tenant-env ns]
GRADLE[GradleJob<br/>build / test]
KANIKO[KanikoJob<br/>image build]
end
USER([User browser]) -- "SSE /api/conversations/{id}/stream" --> BE
BE -- "POST /sessions, /messages,<br/>HMAC X-Worker-Token" --> WORKER
WORKER -- "Anthropic SDK request via fetch baseURL" --> GW
GW -- "fetch + ANTHROPIC_API_KEY" --> ANT[Anthropic API]
WORKER -- "k8s Job dispatch (RoleBinding scoped)" --> GRADLE
WORKER -- "k8s Job dispatch (RoleBinding scoped)" --> KANIKO
WORKER -- "POST /api/internal/worker/* reports<br/>HMAC X-Worker-Token" --> BE
Klíčové momenty:
- User → BE SSE — browser drží jednu SSE konekci na control-plane BE; BE forwarduje eventy z workeru (které worker streamuje k BE) do browseru. User nikdy nekomunikuje přímo s workerem (ten je v tenant-env namespace, nemá svůj Ingress).
- BE → worker — control-plane drží reference na worker Service v tenant-env namespace
(
talkide-worker.{tenant}-{env}.svc.cluster.local). Volání jsou HMAC-podepsaná (X-Worker-Token) — talkide-be#104 seam, který byl re-použit z původního sidecar runtime. - Worker → Gateway-proxy → Anthropic — Anthropic SDK ve workeru má přebookovaný
fetchbaseURL nahttps://api.talkide.app/api/internal/gateway/anthropic. Gateway-proxy v BE drží jedinýANTHROPIC_API_KEY, doplňuje header, proxuje request 1:1. - Worker → BE reporting — tool-use events, usage tokens, activity log a UC-09 issue
reporting (
talkide-issue-trackingMCP server v workeru) jdou zpět HMAC kanálem na/api/internal/worker/*endpointy v control-plane.
3. Thin-seam kontrakt (control-plane ↔ worker)
ADR-024 § Decision 2 definuje, co zůstává v BE a co přechází do workeru. Operativní upřesnění:
3.1 Co drží control-plane (Spring Boot, ns talkide-prod)
| Doména | Komponenta | Poznámka |
|---|---|---|
| Identity / JWT | AuthFilter, JwtService | Worker JWT nezná — autentizace user requestu končí na BE Ingressu |
| Tenant / project / conversation perzistence | platform DB (cluster A) | Jediný zdroj pravdy pro metadata |
| Worker orchestrace | K8sWorkerProvisioner | Create/delete talkide-worker Deployment v tenant-env ns; healthcheck; rolling restart při worker image upgrade |
| Gateway-proxy | AnthropicGatewayController | Drží ANTHROPIC_API_KEY, accounting, rate-limit, FUP enforcement |
| Quota / budget autorita | UserBudgetService, HostingEnforcementService | Worker se ptá přes gateway-proxy (pre-call check), nikdy nestanoví limity sám |
| HMAC token issuance | WorkerTokenService | Worker token je per-pod, předaný přes K8s Secret v tenant-env ns, validace na BE straně |
3.2 Co drží worker (Node 22+, ns {tenant}-{env})
| Doména | Komponenta | Poznámka |
|---|---|---|
| Mara / Anthropic SDK runtime | Harness.ts, AnthropicHarness | Volá query() SDK in-process, drží AsyncGenerator pro user inputs |
| Session state | CLAUDE_CONFIG_DIR=/data/claude na NFS PVC claude-sessions | Per-conversation SessionStore directory; survives worker restart |
| SSE stream zpět do BE | httpServer.ts, sseWriter.ts | Worker je HTTP server (port 8090); BE volá GET /sessions/{id}/stream |
| Dispatch build/test Jobů | (Plánováno, viz § 7 open) | RBAC: Role v tenant-env ns scopuje CREATE/GET/WATCH/DELETE na batch.Job |
| Issue reporting | talkide-issue-tracking MCP server in-worker (be#139) | Mara může reportovat platform/project issues; doručuje přes HMAC HTTP do BE |
| Activity / usage reporting | recordToolUse events (be#143), token usage | HTTP POST /api/internal/worker/activity + /usage |
3.3 Identity token + mint seam (talkide-be#245)
Worker drží long-lived identity token v env TALKIDE_WORKER_IDENTITY_TOKEN (načteno
z K8s Secret talkide-worker-token, klíč identity-token, v tenant-env ns).
Tento token neslouží přímo k gateway callům — slouží k autentizaci worker→control-plane
mint endpointu (/api/v1/worker-gateway/token/mint), kde worker na začátku každého
Mara turn mintuje čerstvý short-lived WorkerToken (TTL 120 s, scope = conversationId).
Ten pak LocalGatewayProxyServer připojuje k per-request gateway callu.
BE validuje HMAC v WorkerTokenValidationFilter. Bind identity tokenu je per (tenant_id, env_id) —
token nelze přenést mezi tenant-env namespace.
Stejný HMAC mechanismus se používá i v opačném směru (BE → worker), aby worker odmítl volání, která nepřišla z platform BE.
4. HTTP + SSE protokol mezi BE a workerem
Nahradil NDJSON-přes-pipe protokol z původního sidecaru. Detail kontraktu žije v
talkide-worker/src/contract/. Operativně:
4.1 BE → worker (commands)
| Method | Path | Účel |
|---|---|---|
POST | /sessions | Start/resume Mara session pro conversationId |
POST | /sessions/{id}/messages | Push další user message do běžící session |
POST | /sessions/{id}/cancel | Soft cancel — abort SDK, vrátí partial text |
DELETE | /sessions/{id} | Hard stop session, uvolnit z worker memory |
GET | /sessions/{id}/stream | SSE stream eventů (worker drží connection alive) |
GET | /healthz | Liveness/readiness probe |
4.2 Worker → BE (events přes SSE response k commandu /sessions/{id}/stream)
| Event name | Payload | Mapuje na |
|---|---|---|
assistant_chunk | { text } | Akumuluje se v BE, předává klientovi přes user-facing SSE |
assistant_complete | { fullText } | BE uloží message do messages tabulky |
tool_use | { toolName, toolUseId, parentId?, ... } | BE RecordActivityUseCase.recordToolUse (be#143 — Activity panel) |
subagent_start | { subagentType, taskId } | Activity log |
subagent_complete | { taskId } | Activity log |
cancelled | { partialText? } | BE uloží jako CANCELLED message |
error | { message } | BE error handling |
heartbeat | {} | 30s keep-alive |
4.3 Worker → BE (reporting kanál, sync HTTP)
| Method | Path | Účel |
|---|---|---|
POST | /api/internal/worker/activity | TOOL_USE / TASK_STARTED / TASK_COMPLETED audit events |
POST | /api/internal/worker/usage | Token usage (input/output/cache) pro UserBudget accounting |
POST | /api/internal/worker/issues | UC-09 issue reporting (Mara MCP talkide-issue-tracking, be#139) |
5. Session resume strategie
5.1 NFS-backed CLAUDE_CONFIG_DIR
Worker pod mountuje PVC claude-sessions (ReadWriteMany NFS) na /data/claude. Anthropic
Agent SDK perzistuje session state (transcript, tool call history, sub-agent context) do
$CLAUDE_CONFIG_DIR/projects/{conversationId}/.
Důsledky:
- Worker pod restart → SDK
resume(conversationId)rekonstruuje session z NFS. Žádný BE retry s historií z DB (Variant B z původního sidecar specu) není potřeba — SDK to zvládne sám. - BE redeploy → worker pod žije dál, SSE/HTTP konekce z BE se re-establishují.
- Worker image upgrade → orchestrace přes rolling update; nová replika pickne sessions z NFS.
5.2 ADR-024 cut-over invariant
Durable session state MUSÍ žít ve SessionStore v talkide-worker (NFS PVC). User upozornění
sender (h@webuild.software, mailing announcement) je gated na ověřený worker provoz —
viz CLAUDE.md “Cutover #269 stav”.
6. Gateway-proxy (Anthropic call mediator)
6.1 Proč gateway
| Důvod | Detail |
|---|---|
| Klíčový secret nikdy mimo control-plane | ANTHROPIC_API_KEY žije jen v BE K8s Secret v ns talkide-prod. Kompromitace worker podu v tenant-env ns neexponuje klíč. |
| Centralizovaný accounting | UserBudget debit, FUP rate-limit, BOGO bonus aplikace — vše v jednom místě (UC-08001 apply-markup-to-billing, UC-10008). |
| Easy rotation | Rotace klíče = restart BE podu; worker je nezávislý. |
| Per-request quota check | Gateway může odmítnout call pokud UserBudget.spending_limit_usd přesažen — viz UC-10005. |
6.2 Tok jednoho turn
sequenceDiagram
participant W as Worker (Anthropic SDK)
participant GW as Gateway-proxy (BE)
participant UB as UserBudgetService
participant ANT as Anthropic API
W->>+GW: POST /api/internal/gateway/anthropic/v1/messages<br/>X-Worker-Token: HMAC
GW->>GW: validate HMAC, resolve (tenant, env)
GW->>+UB: preCallCheck(userId, estimatedCost)
UB-->>-GW: ALLOW / DENY (spending limit / FUP)
alt DENY
GW-->>W: 429 Too Many Requests
else ALLOW
GW->>+ANT: forward request + ANTHROPIC_API_KEY
ANT-->>-GW: streaming response
GW-->>W: streaming response (passthrough)
GW->>UB: postCallDebit(userId, actualCost, tokens)
end
deactivate GW
Poznámka — in-worker vrstva:
Worker (Anthropic SDK)v diagramu nahoře je zjednodušení. Mezi SDK subprocess a gateway-proxy (BE) existuje ještěLocalGatewayProxyServer(in-process v worker podu), který per-request mintuje čerstvýWorkerTokena teprve pak forwarduje request na BE gateway. Detailní architektura: viz § 6.3 níže.
6.3 Co worker volá — LocalGatewayProxyServer architektura
Worker nevolá new Anthropic({ baseURL, authToken }) přímo s gateway URL. Skutečná
architektura (post talkide-be#245, implementováno v AnthropicAgentSdkHarness.ts):
AnthropicAgentSdkHarnessstartujeLocalGatewayProxyServerin-process nalocalhost:<dynamic-port>. Tento server poslouchá na URL tvaruhttp://127.0.0.1:<port>.- SDK subprocess dostane env:
ANTHROPIC_BASE_URL=http://127.0.0.1:<port>/<conversationId> ANTHROPIC_AUTH_TOKEN=<inert-placeholder> # povinné — CLI short-circuits bez credentialANTHROPIC_API_KEYje explicitně odstraněn z env (§C4 invariant). LocalGatewayProxyServerzachytí každý Anthropic SDK request, smaže příchozíAuthorizationheader a nahradí ho čerstvě mintnutýmWorkerToken: volá control-plane mint endpoint ($TALKIDE_GATEWAY_BASE_URL/api/v1/worker-gateway/token/mint) autentizovaný pomocíTALKIDE_WORKER_IDENTITY_TOKEN. Minted token má TTL 120 s a scopeconversationId— per request, nikdy neprošlý.- Takto obohatený request je forwardován na control-plane gateway (
$TALKIDE_GATEWAY_BASE_URL).
Env var pro gateway URL: TALKIDE_GATEWAY_BASE_URL.
Implementace: talkide-worker/src/gateway/GatewayProxy.ts (interface + MintingGatewayProxy),
talkide-worker/src/harness/anthropic/AnthropicAgentSdkHarness.ts (buildSdkEnv, ensureLocalProxy).
Dev/lokál:
NoOpGatewayProxyje pre-E.4 stub — forwarduje volání přímo na Anthropic bez gateway. Slouží pro lokální testování workeru bez TalkIDE BE.
7. Otevřené body (cílový stav, in-flight)
7.1 Build/test K8s Job dispatch z workeru
Plán dle ADR-024 § Decision 4 — gradle build/test jako ephemeral K8s Joby v tenant-env ns,
dispatchnuté přímo workerem (RBAC Role + RoleBinding scopující CREATE/GET/WATCH/DELETE
na batch.Job v daném ns).
Stav 2026-05-23: implementační prerekvizita pro post-alpha škálování. V současné alpha
fázi (1–3 tenanti) build/test pořád běží v rámci BE workflow (GradleJobBuilder analogický
KanikoJobBuilder ještě nevznikl).
Mitigace cold-start latence (NFS gradle cache, pre-pulled builder image, reused cache volume) je popsaná v ADR-024 § Consequences 1.
7.2 NFS gradle cache RWM vs. RWO
Open design: ReadWriteMany PVC sdílený přes Joby vs. ReadWriteOnce per-job. Interní task
#266 — nemá GitLab issue. Vliv na concurrency limit pro paralelní buildy.
7.3 Build node pool topologie
Eskalováno do infra#21 (priority::high po incidentu 2026-05-23). Dedikovaný build node pool pro odolnost vůči “noisy neighbor” na worker podech.
7.4 Worker MCP servery — rozšíření nad talkide-issue-tracking
Aktuálně worker exponuje jeden MCP server pro Maru: talkide-issue-tracking (be#139, LIVE).
Mara má jen headless toolset (žádný browser MCP, žádné IDE pluginy). Budoucí MCP servery
(např. database inspector) by žily v workeru přímo nebo přes .mcp.json v project working
tree na NFS — open design.
7.5 Worker token rotation
Aktuálně identity token je stabilní v K8s Secret talkide-worker-token (klíč identity-token,
env TALKIDE_WORKER_IDENTITY_TOKEN, default TTL 90 dní). Rotace = re-mint identity token
přes K8sWorkerProvisioner + update secret + restart workeru. Otevřená otázka: automatická
rotace + grace period (dva tokeny souběžně validní) pro zero-downtime rotaci. Post-alpha.
8. Vztah k jiným ADR a specifikacím
| Reference | Vztah |
|---|---|
| ADR-024 | Zdroj pravdy pro extrakční rozhodnutí — tento dokument je operativní rozšíření |
| ADR-023 §5 | Namespace-per-tenant-env je substrát workeru |
| ADR-026 | Environment first-class koncept — worker pod žije v {tenant}-{env} ns |
| ADR-019 | Kaniko Job pattern, který se rozšiřuje na gradle/test Joby (§ 7.1) |
| worker-production.md | Production readiness — resource limits, observability, image build, secrets |
| runtime-dependencies.md | Node verze, Anthropic SDK verze, system tools |
9. Co bylo a už není (historie)
Thanks for the feedback.