title: OrgState API
emoji: π
colorFrom: blue
colorTo: indigo
sdk: docker
app_port: 8080
suggested_hardware: cpu-basic
pinned: false
OrgState API on Hugging Face Spaces
This Space runs the OrgState drift-detection API. Two deployment modes:
- Free production (recommended) β point the Space at an external Postgres (Neon free tier or Supabase free tier). The DB persists through every Space restart. Use this for any deployment that has customers, even pilots.
- Demo-only β leave the default
ORGSTATE_DB_PATH=/data/orgstate. sqlite3. Data is wiped on every Space restart since HF's free CPU tier has no persistent storage. Use only for "click around the UI" demos with no real users.
Both modes use the same Dockerfile + Space configuration. The choice is one env var.
Endpoints
GET /healthβ liveness probeGET /health/readyβ readiness probeGET /metricsβ PrometheusGET /docsβ Swagger UI with paste-ready examplesPOST /tenants/{tid}/...β see Swagger UI
Free production setup (HF + Neon)
Neon Postgres β sign in to neon.tech, create a new project ("orgstate"). Copy the connection string from the project dashboard. It looks like:
postgresql://neondb_owner:xxx@ep-yyy-pooler.region.aws.neon.tech/neondb?sslmode=requireNeon's free tier (0.5GB storage shared across projects, no card) is plenty for the first 10k tenant rows + 1M audit rows. Storage is shared across all projects in the account β if you're tight, switch to Supabase (supabase.com) which has a separate quota (500MB per account).
HF Space variables (Settings β Variables and secrets):
ORGSTATE_DB_PATH= the Neon connection string aboveORGSTATE_ADMIN_KEY=openssl rand -hex 16outputORGSTATE_CORS_ORIGINS= your dashboard origin (e.g.https://orgstate.1bigfam.com)ORGSTATE_HSTS_ENABLED=falseinitially (HF's TLS terminator is fine, but enable only AFTER you've verified your dashboard loads cleanly β HSTS pins formax-age=1 yearby default and a misconfig will brick browsers for the duration)
Push the repo to your Space:
git remote add hf https://huggingface.co/spaces/<username>/orgstate-api git push hf masterFirst build takes ~5 min (pip install heavy line is psycopg's binary wheel + cryptography). Subsequent rebuilds are fast.
Verify at
https://<username>-orgstate-api.hf.space/docs. You should see the Swagger UI listing every/v1/...and/scim/v2/...endpoint.Bootstrap the first tenant + API key:
# against the live URL, using the admin key you set above curl -X POST https://<...>.hf.space/v1/tenants \ -H "Authorization: Bearer $ORGSTATE_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{"tenant_id":"acme","name":"ACME Inc"}' # mint a per-tenant API key (shown ONCE): curl -X POST https://<...>.hf.space/v1/tenants/acme/keys \ -H "Authorization: Bearer $ORGSTATE_ADMIN_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"admin"}'Paste the returned
rawvalue into the dashboard's "Sign in" form.Drop the bootstrap admin key from HF env once a DB-backed admin key exists (the platform falls back to DB-backed admins; the env key is only needed for the first POST
/tenants).
Demo-only setup (HF + SQLite ephemeral)
Skip the Neon step. Set only ORGSTATE_ADMIN_KEY and (optionally)
ORGSTATE_CORS_ORIGINS. The DB lives at /data/orgstate.sqlite3 and
gets wiped on every restart. Demo data must be re-seeded; see the
gtm/ directory for sample fixtures.
Limits (both modes)
- HF auto-sleeps after 48h of no traffic. The first request after sleep takes 30-60s to wake the container. Subsequent requests are normal. The dashboard handles this gracefully (loading state on 502) but cron jobs hitting the API will see occasional failures during cold start.
- No scheduler process. HF Spaces runs a single container; the
background ingestion scheduler isn't started. Manually trigger runs
via the dashboard or
POST /tenants/{tid}/observations/run. - Rate limits apply. Defaults are 600 rpm per credential, 60 rpm
per IP (see Stage 79). Tighten via
ORGSTATE_RATE_LIMIT_PER_KEY. - No HSTS by default β flip
ORGSTATE_HSTS_ENABLED=trueonly AFTER the dashboard works end-to-end on HTTPS. HSTS pins for a year and a misconfig is hard to roll back.
When to graduate off HF
HF free is fine through your first 10-20 customers OR a few thousand SCIM users. The signals to graduate:
- Cold-start latency hurts (real customers complain about the 30s wake delay).
- You exceed Neon's free 0.5GB quota β bump to Neon's $19/mo tier OR migrate to Supabase pro / self-hosted Postgres.
- You need a scheduler process β pick Fly (
deploy/fly.toml) or Render (deploy/render.yaml) which support multi-process apps.
Replacing this README
In your Space repo root, copy this file as README.md and adjust the
frontmatter (title/emoji/colors). The frontmatter drives Spaces' UI;
the body is what users see when they visit the Space page.