Skip to content
omnidotdevPublic

About

🔶 Write code, get geometry (Facet API)

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

📐 Facet API

The Facet AI generation gateway. A thin Elysia service whose entire job is to call the Synapse AI router safely, so natural-language prompts become parametric CAD code without ever exposing our model keys or letting anyone run up a bill against them.

Facet itself stays a static SPA for local modeling. This gateway owns the one thing the browser must never hold: the server-side Synapse key. It builds a grounded prompt from the Facet authoring API, calls Synapse's Anthropic-compatible POST /v1/messages, extracts the fenced TypeScript block, and returns it with a usage estimate. Every layer of the money-safety model lives here.

What it exposes

Method Path Purpose
POST /generate Turn a prompt into Facet TypeScript. Managed (our key) or BYOK (caller's key).
GET /health Liveness.
GET /ready Readiness (DB connectivity, used from Phase C on).

POST /generate

Request:

{
  "prompt": "a 20mm cube with a 6mm hole through it",
  "byokKey": "sk-ant-...",          // optional, bring-your-own-key
  "previous": {                      // optional, repair turn
    "code": "<prior code>",
    "error": "<kernel error text>"
  }
}

The managed path (no byokKey) requires a signed-in Omni user: send the user's access token as Authorization: Bearer <token> (the same Better Auth / Gatekeeper token the rest of the fleet uses). A missing or invalid token returns 401; a user who has spent all their monthly credits returns 402. BYOK requests need no auth and are not credit-metered.

Response:

{
  "code": "const part = cube(20).subtract(cylinder(3, 24));\nreturn part;",
  "usage": { "credits": 2, "costCents": 1.4 }
}
  • credits is ceil(costCents) (1 credit ~= $0.01 of model spend).
  • The previous field drives the client-side repair loop: on a kernel throw the app re-calls /generate with the failing code plus the error so the model can fix it.

Money-safety model

Defense-in-depth. Each layer is independent, so a bug in one does not defeat the others:

  1. Server-only key. SYNAPSE_API_KEY lives only here, never VITE_-prefixed, never shipped to the browser, never written to a response body or a log.
  2. Synapse-key hard budget. The provisioned key carries a hard monthly ceiling set in Synapse (Phase D), bounding worst-case total loss.
  3. Global daily spend breaker. Aggregate managed spend is tracked per UTC day; /generate returns 503 once DAILY_SPEND_CEILING_CENTS is hit.
  4. Auth-gated managed path. The managed path requires a valid signed-in Omni identity (bearer token verified via Gatekeeper); no anonymous access to paid inference, 401 otherwise.
  5. Per-user hard-capped credits. Managed usage is metered per user per UTC month against FREE_MONTHLY_CREDITS with no overage; /generate returns 402 once the cap is reached. Usage is persisted in the credit_ledger table, so the cap holds across instances and restarts.
  6. Per-request caps. MAX_PROMPT_CHARS, MAX_OUTPUT_TOKENS, a request timeout, and MAX_REPAIR_ATTEMPTS, all enforced server-side.
  7. Per-IP rate limit. Sliding-window limiter on /generate; 429 on exceed.
  8. BYOK escape hatch. A caller may send their own key per-request over TLS. It is never persisted, bills to them, and bypasses auth, the managed breaker, and the credit meter entirely.

The per-user credit meter is DB-backed. The global daily breaker and per-IP rate limiter stay in-memory: the Synapse-key hard budget plus the per-user cap already bound worst-case loss, so moving them to a shared store is deferred (see the TODOs in src/lib/cost/breaker.ts and rateLimit.ts). The per-user cap is read from FREE_MONTHLY_CREDITS for now and will be sourced from Aether entitlements in Phase D.

Environment

The service boots with nothing set. Every variable is optional; the managed path is the only feature that needs configuration, and it degrades to a clean 503 (with a startup warning) when its key is absent.

Variable Default Purpose
SYNAPSE_BASE_URL http://localhost:6000 Synapse AI router base URL.
SYNAPSE_API_KEY (unset) Server-side Synapse key. Unset disables the managed path (BYOK still works). Never shipped to the browser.
SYNAPSE_API_URL (unset) Synapse provisioning API (api.synapse, not the gateway). With SYNAPSE_GATEWAY_SECRET, enables per-user managed keys.
SYNAPSE_GATEWAY_SECRET (unset) Gateway secret for the internal provisioning call. With SYNAPSE_API_URL, enables per-user managed keys (additive; the credit ledger still hard-caps).
FACET_AI_MODEL claude-sonnet-5-5 Claude model id passed through to Synapse.
MAX_PROMPT_CHARS 2000 Maximum accepted prompt length.
MAX_OUTPUT_TOKENS 2048 Output token ceiling per call.
AI_REQUEST_TIMEOUT_MS 30000 Synapse request timeout.
MAX_REPAIR_ATTEMPTS 2 Repair-attempt ceiling per generation.
DAILY_SPEND_CEILING_CENTS 500 Global managed spend breaker, per UTC day.
FREE_MONTHLY_CREDITS 100 Per-user hard cap on managed credits per UTC month.
RATE_LIMIT_WINDOW_MS 60000 Per-IP rate-limit window.
RATE_LIMIT_MAX 20 Max requests per IP per window.
AUTH_BASE_URL https://localhost:8000 Gatekeeper base URL used to verify the managed path's bearer token.
DATABASE_URL (unset) Postgres connection for the credit meter. The managed path needs it; BYOK does not.

The managed path depends on SYNAPSE_API_KEY, AUTH_BASE_URL, and DATABASE_URL; BYOK needs none of them. GraphQL and Vortex variables remain scaffolding. See .env.local.template for the full list.

Local development

cp .env.local.template .env.local   # optional, the service boots with no env set
bun install
bun dev

The service boots with no env configured: if SYNAPSE_API_KEY is unset it logs a warning and the managed path returns a clean 503, while BYOK requests still work. See .env.local.template for required vs optional variables.

Testing

bun test            # no database required for Phase A
bun run check       # Biome lint + format
bunx tsc --noEmit   # type check
bun run knip        # dead code + unused deps
bun run build       # bundle

License

The code in this repository is licensed under Apache 2.0, © Omni LLC. See LICENSE.md for more information.

About

🔶 Write code, get geometry (Facet API)

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages