# rdev v0.4.0 - API Server **Date**: 2026-01-24 **Status**: Ready for deployment ## Summary Go REST API server for controlling claudebox pods. External clients (Discord bots, CLI tools, etc.) can now interact with Claude Code via HTTP endpoints with SSE streaming for real-time output. ## What Was Built ### Go API Server (`rdev-api`) A chi-based HTTP server with: - Project discovery and status - Command execution (claude, shell, git) - SSE streaming for real-time output - OpenAPI documentation via Scalar ### API Endpoints | Method | Path | Description | |--------|------|-------------| | GET | `/health` | Health check | | GET | `/ready` | Readiness check | | GET | `/docs` | Scalar API documentation | | GET | `/openapi.json` | OpenAPI 3.0 specification | | GET | `/projects` | List available projects | | GET | `/projects/{id}` | Get project details | | POST | `/projects/{id}/claude` | Run Claude command | | POST | `/projects/{id}/shell` | Run shell command | | POST | `/projects/{id}/git` | Run git command | | GET | `/projects/{id}/events` | SSE stream for output | ### Packages Created ``` cmd/rdev-api/ └── main.go # Entry point, OpenAPI spec pkg/api/ ├── app.go # HTTP server chassis ├── response.go # JSON response helpers └── openapi.go # OpenAPI spec builder internal/ ├── handlers/ │ └── projects.go # HTTP handlers + SSE streaming ├── executor/ │ └── executor.go # kubectl exec wrapper └── projects/ └── registry.go # Project discovery ``` ### Kubernetes Resources - **Deployment**: `rdev-api` - Single replica - **Service**: `rdev-api` - ClusterIP on port 8080 - **ServiceAccount**: `rdev-api` - **Role/RoleBinding**: Permissions for pod exec ### RBAC Permissions ```yaml rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["pods/exec"] verbs: ["create"] - apiGroups: [""] resources: ["pods/log"] verbs: ["get"] ``` ## Files Created ``` Dockerfile.api # API server image cmd/rdev-api/main.go # Entry point pkg/api/app.go # HTTP chassis pkg/api/response.go # Response helpers pkg/api/openapi.go # OpenAPI builder internal/handlers/projects.go # Handlers + SSE internal/executor/executor.go # kubectl exec internal/projects/registry.go # Project registry deployments/k8s/base/rdev-api.yaml # Deployment + Service deployments/k8s/base/rbac.yaml # RBAC go.mod, go.sum # Go modules ``` ## Dependencies ``` github.com/go-chi/chi/v5 # HTTP router github.com/bdpiprava/scalar-go # API documentation ``` ## Deployment Instructions ### 1. Build Images ```bash cd /path/to/rdev # Build both claudebox and api images ./scripts/build-push.sh v0.4.0 # Or just the api ./scripts/build-push.sh v0.4.0 api ``` ### 2. Complete Prerequisites Ensure v0.2 and v0.3 are deployed: - Deploy keys configured for projects - Secrets updated with base64 private keys - claudebox image v0.3.0 with git config ### 3. Deploy ```bash export KUBECONFIG=~/.kube/orchard9-k3sf.yaml kubectl apply -k deployments/k8s/base ``` ### 4. Verify ```bash # Check API is running kubectl get pods -n rdev -l app=rdev-api # Port forward for testing kubectl port-forward -n rdev svc/rdev-api 8080:8080 # Test health endpoint curl http://localhost:8080/health # Test projects list curl http://localhost:8080/projects # Test Claude command curl -X POST http://localhost:8080/projects/pantheon/claude \ -H "Content-Type: application/json" \ -d '{"prompt": "what files are in this project?"}' # View API docs open http://localhost:8080/docs ``` ## Usage Examples ### Run Claude Command ```bash # Start command curl -X POST http://rdev-api.rdev.svc:8080/projects/pantheon/claude \ -H "Content-Type: application/json" \ -d '{"prompt": "fix the bug in auth handler"}' # Response { "data": { "id": "cmd-pantheon-001", "project": "pantheon", "type": "claude", "status": "running", "stream_url": "/projects/pantheon/events?stream_id=cmd-pantheon-001" }, "meta": {"request_id": "...", "timestamp": "..."} } ``` ### Stream Output (SSE) ```javascript const events = new EventSource( 'http://rdev-api.rdev.svc:8080/projects/pantheon/events?stream_id=cmd-pantheon-001' ); events.addEventListener('output', (e) => { const data = JSON.parse(e.data); console.log(`[${data.stream}] ${data.line}`); }); events.addEventListener('complete', (e) => { const data = JSON.parse(e.data); console.log(`Done: exit=${data.exit_code}, ${data.duration_ms}ms`); events.close(); }); ``` ### Run Shell Command ```bash curl -X POST http://rdev-api.rdev.svc:8080/projects/pantheon/shell \ -H "Content-Type: application/json" \ -d '{"command": "go test ./..."}' ``` ### Run Git Command ```bash curl -X POST http://rdev-api.rdev.svc:8080/projects/pantheon/git \ -H "Content-Type: application/json" \ -d '{"args": ["status"]}' ``` ## Architecture ``` ┌─────────────────────────────────────────────────────────────┐ │ rdev namespace │ │ │ │ ┌──────────────┐ │ │ │ rdev-api │ │ │ │ (Go server) │ │ │ │ │ │ │ │ /projects │ kubectl exec │ │ │ /claude │─────────────────┐ │ │ │ /shell │ │ │ │ │ /git │ ▼ │ │ │ /events │ ┌──────────────────────────────────────┐ │ │ └──────────────┘ │ claudebox pods │ │ │ │ │ │ │ │ ┌────────────────┐ ┌──────────────┐ │ │ │ │ │claudebox- │ │claudebox- │ │ │ │ │ │pantheon-0 │ │aeries-0 │ │ │ │ │ │ │ │ │ │ │ │ │ │ Claude Code │ │ Claude Code │ │ │ │ │ │ /workspace │ │ /workspace │ │ │ │ │ └────────────────┘ └──────────────┘ │ │ │ └──────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ## What's Next (v0.5) Enhanced SSE streaming: - Output buffering and chunking - Connection management (heartbeats, reconnection) - Event filtering by stream_id - Better error handling ## Troubleshooting ### API returns 404 for project - Check project registry includes the project - Verify claudebox pod exists: `kubectl get pods -n rdev` ### Commands fail with "permission denied" - Check RBAC is applied: `kubectl get role rdev-api -n rdev` - Verify ServiceAccount is bound: `kubectl get rolebinding rdev-api -n rdev` ### SSE not receiving events - Ensure stream_id matches the command ID - Check for Connection: keep-alive in client - Verify no proxy is buffering responses