v0.2 - Real Workspaces: - Project-specific claudebox StatefulSets (pantheon, aeries) - Init containers for git clone via SSH - Deploy key secrets template - Project ConfigMaps for CLAUDE.md v0.3 - Git Integration: - Dockerfile with rdev-bot git identity - openssh-client for SSH operations - Image version bump to v0.3.0 v0.4 - API Server: - Go REST API with chi router - Endpoints: /projects, /claude, /shell, /git, /events - SSE streaming for real-time output - OpenAPI docs via Scalar at /docs - Kubernetes RBAC for pod exec - Executor and project registry packages Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
8.0 KiB
8.0 KiB
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
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
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
export KUBECONFIG=~/.kube/orchard9-k3sf.yaml
kubectl apply -k deployments/k8s/base
4. Verify
# 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
# 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)
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
curl -X POST http://rdev-api.rdev.svc:8080/projects/pantheon/shell \
-H "Content-Type: application/json" \
-d '{"command": "go test ./..."}'
Run Git Command
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