Skip to content

katago-service

apps/katago-service is a thin NestJS service whose only job is to spawn the KataGo binary, serialise requests to its GTP-shaped stdin/stdout JSON, and return structured responses. It exposes two transports so the gateway can talk to it however it prefers, and a BullMQ queue so multiple weiqi-server instances can share a single KataGo budget.

KataGoHttpController (src/katago/katago-http.controller.ts:17) accepts:

POST /v1/analysis?priority=1
Content-Type: application/json
{ "id": "...", "analyzeOptions": { ... } }

priority is optional; it overrides the default worker priority (DEFAULT_ANALYSIS_PRIORITY=1) for this request.

Proto at apps/katago-service/proto/katago.proto, package katago.v1, service KataGoService (src/katago/katago-grpc.controller.ts:6). Methods:

RPCUse case
AnalyzeSyncSynchronous: returns when KataGo finishes.
AnalyzeAsyncFire-and-forget: returns a jobId, fetch result via GetResult.
GetJobQuery current state of a job.
GetResultFetch a finished job’s result.
GetHealthLiveness + active job count.
GetVersionKataGo binary version + git hash.

analyze_options arrives as a JSON string in proto. The gateway sends the canonical analyzeTurns array here for full-game review.

adapters/engine/:

  • KataGoBinaryEngineAdapter (katago-binary.engine.ts:155) — spawns the KataGo binary (KATAGO_PATH, default katago), pipes JSON requests on stdin, parses JSON lines on stdout. Caches the process handle per worker.
  • MockKataGoEngine — deterministic test double.

The active adapter is chosen at boot. There is no A/B — pick by env.

BullMQ queue katago-analysis decouples weiqi-server from KataGo’s actual throughput. WeiQiServerKatagoProcessor (adapters/queue/weiqiserver-katago.processor.ts:89) consumes jobs and shares a PrioritySemaphoreKataGoConcurrencyGuard (adapters/concurrency/priority-semaphore.guard.ts) so the configured caps are global across all workers.

Env knobs:

  • KATAGO_MAX_CONCURRENT — max simultaneous KataGo processes.
  • KATAGO_RATE_LIMIT_MAX — rate-limit cap.
  • KATAGO_RATE_LIMIT_DURATION_MS — rate-limit window.

Worker priority is set per-job (priority field). Lower number = higher priority (BullMQ convention).

PORT=4011
GRPC_PORT=50051
KATAGO_PATH=katago # binary on $PATH
KATAGO_MODEL_PATH= # absolute path to .bin.gz model file
KATAGO_CONFIG_PATH= # absolute path to GTP config
QUEUE_MODE=none # "bullmq" to enable queueing
REDIS_URL=redis://localhost:6379

QUEUE_MODE=none makes the service answer directly. Set to bullmq once you have multiple weiqi-server replicas or want to share capacity.

Terminal window
cp apps/katago-service/.env.example apps/katago-service/.env
# Install the KataGo binary and place a model file somewhere on disk.
# Then update KATAGO_PATH / KATAGO_MODEL_PATH / KATAGO_CONFIG_PATH.
pnpm --dir apps/katago-service dev

Smoke test:

Terminal window
curl -s -X POST http://localhost:4011/v1/analysis \
-H 'content-type: application/json' \
-d '{"id":"smoke","analyzeOptions":{"boardXSize":19,"boardYSize":19,"rules":"chinese","analyzeTurns":[0]}}'

weiqi-server does not shell out to KataGo directly for two reasons:

  1. Process isolation. A crashing KataGo process takes the worker down but not the gateway.
  2. Capacity sharing. When weiqi-server scales horizontally, every replica can post jobs to the same queue and a single katago-service instance (or pool) drains them under one concurrency cap.

See KataGo Review for how the queue is used in the unified full-game review flow.