- RUNBOOK.md: k3s/FPGA/Tailscale/GPU/DNS ops procedures - FPGA_PROGRAMMING_GUIDE.md: SUBLEQ format, memory map, 3 examples - DISASTER_RECOVERY.md: backup/restore for all components - API_DOCS.md: dashboard, credential, registry, jobs, blobs APIs
8.2 KiB
API Documentation — Research Stack Services
Last updated: 2026-05-29
Base URL: https://researchstack.info
Auth: Authentik OIDC (SSO) or Bearer token (API endpoints)
Authentication
OIDC (SSO) — Web Endpoints
Web-facing endpoints use Authentik OIDC. Access via browser redirects to auth.researchstack.info.
Token Auth — API Endpoints
API endpoints (/api/*) use Bearer token authentication:
Authorization: Bearer <token>
Tokens are managed by the Credential Server.
Cluster Dashboard
Namespace: monitoring
Internal URL: http://cluster-dashboard:8787
External URL: https://researchstack.info/server/dash/ (via Homarr)
Tech: FastAPI + Vite
Endpoints
GET /
Dashboard UI (Vite SPA).
GET /api/status
Cluster health summary.
Response:
{
"nodes": [
{
"name": "nixos-laptop",
"status": "Ready",
"ip": "100.102.173.61",
"roles": "control-plane",
"version": "v1.35.4+k3s1"
}
],
"pods": {
"total": 24,
"running": 23,
"pending": 0,
"failed": 1
},
"namespaces": ["services", "media", "monitoring", "ai-models", "edge", "research", "mail"]
}
GET /api/metrics
Prometheus-compatible metrics.
WebSocket /ws/live
Real-time cluster events stream.
Message format:
{
"type": "pod_event",
"namespace": "services",
"pod": "homer-abc123",
"status": "Running",
"timestamp": "2026-05-29T12:00:00Z"
}
Credential Server
Namespace: services
Internal URL: http://credential-server:8080
External URL: https://researchstack.info/api/cred/
Auth: Bearer token
Endpoints
GET /api/cred/health
Health check.
Response: 200 OK
{"status": "ok"}
GET /api/cred/tokens
List available tokens (requires admin token).
Response:
{
"tokens": [
{"name": "registry", "scope": "read,write", "expires": "2026-12-31"},
{"name": "jobs", "scope": "read,write,execute", "expires": "2026-12-31"}
]
}
POST /api/cred/issue
Issue a new token.
Request:
{
"name": "service-name",
"scope": "read,write",
"ttl": "30d"
}
Response:
{
"token": "rs_tk_...",
"expires": "2026-06-29T12:00:00Z"
}
POST /api/cred/validate
Validate a token.
Request:
{"token": "rs_tk_..."}
Response:
{
"valid": true,
"name": "registry",
"scope": "read,write"
}
Registry API
Namespace: services
Internal URL: http://registry-api:8080
External URL: https://researchstack.info/api/registry/
Auth: Bearer token
Endpoints
GET /api/registry/health
Health check.
GET /api/registry/artifacts
List all registered artifacts.
Query Parameters:
type— Filter by artifact type (e.g.,bitstream,lean-build,receipt)since— ISO 8601 timestamplimit— Max results (default: 50)
Response:
{
"artifacts": [
{
"id": "art_abc123",
"name": "research_stack_top.fs",
"type": "bitstream",
"size": 184320,
"sha256": "...",
"created": "2026-05-29T10:00:00Z",
"tags": ["fpga", "production"]
}
],
"total": 42
}
POST /api/registry/artifacts
Register a new artifact.
Request:
{
"name": "research_stack_top.fs",
"type": "bitstream",
"sha256": "...",
"blob_ref": "blob_xyz",
"tags": ["fpga"]
}
GET /api/registry/artifacts/{id}
Get artifact by ID.
PUT /api/registry/artifacts/{id}
Update artifact metadata.
DELETE /api/registry/artifacts/{id}
Remove artifact registration (does not delete blob).
Jobs API
Namespace: services
Internal URL: http://jobs-api:8080
External URL: https://researchstack.info/api/jobs/
Auth: Bearer token
Endpoints
GET /api/jobs/health
Health check.
GET /api/jobs
List jobs.
Query Parameters:
status— Filter:pending,running,completed,failedtype— Filter by job typelimit— Max results (default: 20)
Response:
{
"jobs": [
{
"id": "job_abc123",
"type": "lean-build",
"status": "completed",
"created": "2026-05-29T10:00:00Z",
"started": "2026-05-29T10:00:05Z",
"finished": "2026-05-29T10:05:30Z",
"result": {
"jobs": 3572,
"errors": 0
}
}
],
"total": 156
}
POST /api/jobs
Create a new job.
Request:
{
"type": "lean-build",
"params": {
"target": "Semantics",
"branch": "main"
},
"priority": "normal"
}
Response:
{
"id": "job_def456",
"status": "pending",
"created": "2026-05-29T12:00:00Z"
}
GET /api/jobs/{id}
Get job status and result.
POST /api/jobs/{id}/cancel
Cancel a pending or running job.
GET /api/jobs/{id}/logs
Stream job logs (Server-Sent Events).
Response: text/event-stream
data: {"line": "Building Semantics...", "ts": "2026-05-29T12:00:01Z"}
data: {"line": "3572 jobs, 0 errors", "ts": "2026-05-29T12:05:30Z"}
Blobs API
Namespace: services
Internal URL: http://blobs-api:8080
External URL: https://researchstack.info/api/blobs/
Auth: Bearer token
Endpoints
GET /api/blobs/health
Health check.
POST /api/blobs
Upload a blob.
Request: multipart/form-data
file— Binary file contentsha256— Expected SHA-256 hash (verification)
Response:
{
"id": "blob_xyz789",
"size": 184320,
"sha256": "...",
"created": "2026-05-29T12:00:00Z"
}
GET /api/blobs/{id}
Download a blob.
Response: application/octet-stream with blob content.
HEAD /api/blobs/{id}
Check blob existence.
Response: 200 OK (exists) or 404 Not Found
DELETE /api/blobs/{id}
Delete a blob.
GET /api/blobs
List blobs.
Query Parameters:
limit— Max resultsoffset— Pagination offset
Authentik — OIDC Configuration
URL: https://auth.researchstack.info
Protocol: OpenID Connect
Provider Configuration
| Field | Value |
|---|---|
| Authorization URL | https://auth.researchstack.info/application/o/authorize/ |
| Token URL | https://auth.researchstack.info/application/o/token/ |
| UserInfo URL | https://auth.researchstack.info/application/o/userinfo/ |
| JWKS URL | https://auth.researchstack.info/application/o/research-stack/jwks/ |
| Issuer | https://auth.researchstack.info/application/o/research-stack/ |
Scopes
| Scope | Description |
|---|---|
openid |
Standard OIDC |
profile |
User profile (name, email) |
email |
Email address |
groups |
Group membership |
Redirect URIs
https://researchstack.info/oidc/callback
https://researchstack.info/apps/chat/oidc/callback
https://researchstack.info/apps/budget/oidc/callback
Application Setup
In Authentik admin:
- Applications → Create → Name:
Research Stack - Providers → Create → OAuth2/OpenID Provider
- Set client type:
Confidential - Set redirect URIs above
- Assign to application
Service Account Tokens
For API-to-API auth (no user interaction):
# Create service account in Authentik
# Admin → Directory → Users → Create
# Type: Service Account
# Get token
curl -X POST https://auth.researchstack.info/application/o/token/ \
-d "grant_type=client_credentials" \
-d "client_id=<service-account-id>" \
-d "client_secret=<service-account-secret>" \
-d "scope=openid"
Common Response Codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad request (invalid parameters) |
| 401 | Unauthorized (missing or invalid token) |
| 403 | Forbidden (insufficient scope) |
| 404 | Not found |
| 409 | Conflict (duplicate resource) |
| 422 | Unprocessable entity (validation error) |
| 500 | Internal server error |
Rate Limits
| Endpoint | Limit | Window |
|---|---|---|
/api/cred/* |
100 req | 1 minute |
/api/registry/* |
200 req | 1 minute |
/api/jobs/* |
50 req | 1 minute |
/api/blobs/* |
100 req | 1 minute |
Rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1685366400