Internal Documentation internal
TalkIDE internal documentation

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-environment namespace ({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:

  1. 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).
  2. 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.
  3. Worker → Gateway-proxy → Anthropic — Anthropic SDK ve workeru má přebookovaný fetch baseURL na https://api.talkide.app/api/internal/gateway/anthropic. Gateway-proxy v BE drží jediný ANTHROPIC_API_KEY, doplňuje header, proxuje request 1:1.
  4. Worker → BE reporting — tool-use events, usage tokens, activity log a UC-09 issue reporting (talkide-issue-tracking MCP 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énaKomponentaPoznámka
Identity / JWTAuthFilter, JwtServiceWorker JWT nezná — autentizace user requestu končí na BE Ingressu
Tenant / project / conversation perzistenceplatform DB (cluster A)Jediný zdroj pravdy pro metadata
Worker orchestraceK8sWorkerProvisionerCreate/delete talkide-worker Deployment v tenant-env ns; healthcheck; rolling restart při worker image upgrade
Gateway-proxyAnthropicGatewayControllerDrží ANTHROPIC_API_KEY, accounting, rate-limit, FUP enforcement
Quota / budget autoritaUserBudgetService, HostingEnforcementServiceWorker se ptá přes gateway-proxy (pre-call check), nikdy nestanoví limity sám
HMAC token issuanceWorkerTokenServiceWorker 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énaKomponentaPoznámka
Mara / Anthropic SDK runtimeHarness.ts, AnthropicHarnessVolá query() SDK in-process, drží AsyncGenerator pro user inputs
Session stateCLAUDE_CONFIG_DIR=/data/claude na NFS PVC claude-sessionsPer-conversation SessionStore directory; survives worker restart
SSE stream zpět do BEhttpServer.ts, sseWriter.tsWorker 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 reportingtalkide-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 reportingrecordToolUse events (be#143), token usageHTTP 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)

MethodPathÚčel
POST/sessionsStart/resume Mara session pro conversationId
POST/sessions/{id}/messagesPush další user message do běžící session
POST/sessions/{id}/cancelSoft cancel — abort SDK, vrátí partial text
DELETE/sessions/{id}Hard stop session, uvolnit z worker memory
GET/sessions/{id}/streamSSE stream eventů (worker drží connection alive)
GET/healthzLiveness/readiness probe

4.2 Worker → BE (events přes SSE response k commandu /sessions/{id}/stream)

Event namePayloadMapuje 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)

MethodPathÚčel
POST/api/internal/worker/activityTOOL_USE / TASK_STARTED / TASK_COMPLETED audit events
POST/api/internal/worker/usageToken usage (input/output/cache) pro UserBudget accounting
POST/api/internal/worker/issuesUC-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ůvodDetail
Klíčový secret nikdy mimo control-planeANTHROPIC_API_KEY žije jen v BE K8s Secret v ns talkide-prod. Kompromitace worker podu v tenant-env ns neexponuje klíč.
Centralizovaný accountingUserBudget debit, FUP rate-limit, BOGO bonus aplikace — vše v jednom místě (UC-08001 apply-markup-to-billing, UC-10008).
Easy rotationRotace klíče = restart BE podu; worker je nezávislý.
Per-request quota checkGateway 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ý WorkerToken a 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):

  1. AnthropicAgentSdkHarness startuje LocalGatewayProxyServer in-process na localhost:<dynamic-port>. Tento server poslouchá na URL tvaru http://127.0.0.1:<port>.
  2. SDK subprocess dostane env:
    ANTHROPIC_BASE_URL=http://127.0.0.1:<port>/<conversationId>
    ANTHROPIC_AUTH_TOKEN=<inert-placeholder>   # povinné — CLI short-circuits bez credential
    
    ANTHROPIC_API_KEY je explicitně odstraněn z env (§C4 invariant).
  3. LocalGatewayProxyServer zachytí každý Anthropic SDK request, smaže příchozí Authorization header a nahradí ho čerstvě mintnutým WorkerToken: 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 scope conversationId — per request, nikdy neprošlý.
  4. 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: NoOpGatewayProxy je 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

ReferenceVztah
ADR-024Zdroj pravdy pro extrakční rozhodnutí — tento dokument je operativní rozšíření
ADR-023 §5Namespace-per-tenant-env je substrát workeru
ADR-026Environment first-class koncept — worker pod žije v {tenant}-{env} ns
ADR-019Kaniko Job pattern, který se rozšiřuje na gradle/test Joby (§ 7.1)
worker-production.mdProduction readiness — resource limits, observability, image build, secrets
runtime-dependencies.mdNode verze, Anthropic SDK verze, system tools

9. Co bylo a už není (historie)


Was this page helpful?

Thanks for the feedback.