Status: Accepted Date: 2024-11-21 Deciders: Architecture Team Technical Story: Technology stack selection for platform components
We need to choose programming languages for two distinct components:
- Backend API: HTTP server managing Kubernetes resources, authentication, project management
- Claude Code Runner: Executes claude-code CLI in Job pods
What languages should we use for each component, and should they be the same or different?
- Backend needs: HTTP routing, K8s client-go, RBAC, high concurrency
- Runner needs: Claude Code SDK, file manipulation, git operations
- Performance: Backend handles many concurrent requests
- Developer experience: Team expertise, library ecosystems
- Operational: Container size, startup time, resource usage
- Maintainability: Type safety, tooling, debugging
- Go backend + Python runner (chosen)
- All Python (FastAPI backend + Python runner)
- All Go (Go backend + Go wrapper for claude-code)
- Polyglot (Node.js backend + Python runner)
Chosen option: "Go backend + Python runner", because:
Go for Backend:
- K8s ecosystem: client-go is canonical K8s library
- Performance: Low latency HTTP handling, efficient concurrency
- Type safety: Compile-time checks for K8s resources
- Deployment: Single static binary, fast startup
- Team expertise: Red Hat strong Go background
Python for Runner:
- Claude Code SDK: Official SDK is Python-first (
claude-code-sdk) - Anthropic ecosystem: Python has best library support
- Scripting flexibility: Git operations, file manipulation easier in Python
- Dynamic execution: Easier to handle varying prompts and workflows
Positive:
-
Backend:
- Fast HTTP response times (<10ms for simple operations)
- Small container images (~20MB for Go binary)
- Excellent K8s client-go integration
- Strong typing prevents many bugs
-
Runner:
- Native Claude Code SDK support
- Rich Python ecosystem for git/file operations
- Easy to extend with custom agent behaviors
- Rapid iteration on workflow logic
Negative:
-
Maintenance:
- Two language ecosystems to maintain
- Different tooling (go vs. pip/uv)
- Different testing frameworks
-
Development:
- Context switching between languages
- Cannot share code between backend and runner
- Different error handling patterns
Risks:
- Python runner startup slower than Go (~1-2s vs. <100ms)
- Python container images larger (~500MB vs. ~20MB)
- Dependency vulnerabilities in Python ecosystem
Backend (Go):
// Fast HTTP routing with Gin
r := gin.Default()
r.GET("/api/projects/:project/sessions", handlers.ListSessions)
// Type-safe K8s client
clientset, _ := kubernetes.NewForConfig(config)
sessions, err := clientset.CoreV1().Pods(namespace).List(ctx, v1.ListOptions{})Technology Stack:
- Framework: Gin (HTTP routing)
- K8s client: client-go + dynamic client
- Testing: table-driven tests with testify
Runner (Python):
# Claude Code SDK integration
from claude_code import AgenticSession
session = AgenticSession(prompt=prompt, workspace=workspace)
result = session.run()Technology Stack:
- SDK: claude-code-sdk (>=0.0.23)
- API client: anthropic (>=0.68.0)
- Git: GitPython
- Package manager: uv (preferred over pip)
Key Files:
components/backend/- Go backendcomponents/runners/claude-code-runner/- Python runnercomponents/backend/go.mod- Go dependenciescomponents/runners/claude-code-runner/requirements.txt- Python dependencies
Build Optimization:
- Go: Multi-stage Docker build, static binary
- Python: uv for fast dependency resolution, layer caching
Performance Metrics:
- Backend response time: <10ms for simple operations
- Backend concurrency: Handles 100+ concurrent requests
- Runner startup: ~2s (acceptable for long-running sessions)
- Container build time: <2min for both components
Developer Feedback:
- Positive: Go backend very stable, easy to debug
- Positive: Python runner easy to extend
- Concern: Context switching between languages
- Mitigation: Clear component boundaries reduce switching
- Related: ADR-0001 (Kubernetes-Native Architecture)
- client-go documentation
- Claude Code SDK