One gate every model request rides through.
A self-hostable, enterprise-grade LLM gateway: a single container in front of every provider your outfit uses — adding routing, cost control, caching, guardrails, access control, and a tamper-evident audit trail, without changing a line of application code.
Out on the model frontier, traffic rides in from every vendor at once. Gulley is the gate at the pass — it checks the papers, tallies the toll, keeps the ledger, and remembers exactly who rode through.
One control plane over both Claude Code and Codex. Anthropic's and OpenAI's own gateways each govern only their own agent, with after-the-fact, 30-day logs. Gulley is the single in-line, tamper-evident plane over both — plus Bedrock, Vertex, and Azure — with cross-vendor DLP, tool-call policy, hard budgets, and a WORM audit no single-vendor tool can match. It is Claude-first (the Anthropic Messages schema is its canonical internal model) and drop-in: point Claude Code, Codex, or any custom harness at Gulley by changing a base URL, and everything just works — while you gain governance, cost control, and audit over every request.
- Multi-provider, one surface — Anthropic (API + Enterprise), OpenAI, AWS Bedrock, Azure AI Foundry, any OpenAI-compatible backend (Groq, Mistral, Together, …), and local runtimes (Ollama, vLLM, LM Studio); a Google Gemini/Vertex native adapter ships but is not yet configurable. Native full-fidelity passthrough and a cross-provider layer for routing, load-balancing, failover, and same-model arbitrage.
- Governance, all open — RBAC, virtual keys, budgets with hard caps, PII/secret masking, guardrails, and a tamper-evident (hash-chained + S3 Object Lock WORM, KMS-signed, externally anchored) audit trail. Every governance feature is in the Apache-2.0 core — not paywalled behind an "enterprise" edition.
- Coding-agent aware — governs and attributes the traffic Claude Code and Codex actually generate; in-stream (not buffered) source-code / secret DLP; the prompt cache the big cacheable prefixes depend on is metered, so you can see the dollars it saves.
- Enterprise identity — console SSO over OIDC (Microsoft Entra) or SAML 2.0, JWT auth for the data plane, App-Role / group → RBAC with custom roles, SCIM provisioning, Graph-backed revoke-on-deprovision, and workload identity (a Kubernetes service account or GitHub Actions job exchanges its platform token for a scoped, short-lived gateway token — RFC 7523). See
docs/ENTRA_SETUP.md,docs/SAML_SETUP.mdanddocs/WORKLOAD_IDENTITY.md. - Observability without lock-in — emits OpenTelemetry (GenAI semantic conventions) to your backend; enforces cost/rate limits locally; a Prometheus endpoint and a batteries-included admin console. Operational alerts (budgets, key expiry, breakers, guardrail blocks, config applies, break-glass) go to Slack, Teams, PagerDuty, email or a signed webhook — see
docs/ALERTING.md. - Runs where you run — one distroless container for AWS ECS Fargate (a single adaptable Terraform module), Kubernetes (Helm, with an EKS Terraform module), or a docker-compose self-host.
A batteries-included Next.js admin plane — observe spend and traffic, browse the request log, walk the tamper-evident audit chain, manage identity and routing, and edit config as GitOps.
The full design — request pipeline, provider abstraction, auth model, data model, AWS
topology, and a concrete integration-spec appendix — lives in
docs/ARCHITECTURE.md; delivered capabilities are tracked in the
CHANGELOG.
apps/gateway data plane: the streaming proxy + request pipeline
apps/control-api control plane: orgs, keys, routes, policies, OAuth/OIDC, SCIM
apps/web admin console (Next.js)
packages/* core, providers, routing, auth, rbac, budget, ratelimit, cost, catalog,
cache, guardrails, pipeline, config, storage, telemetry, metrics, oauth,
oidc, cel, crypto, worm, redact, egress, http-edge, prompts,
control-client, cli
infra/terraform one adaptable AWS ECS module (test/prod tiers) — see INSTALL.md
infra/eks the EKS sibling module (AWS substrate for the Helm chart)
deploy/ Helm chart + docker-compose self-host
scripts/bundle.mjs esbuild bundling of both apps for the distroless runtime image
Prerequisites: Node ≥ 22.9 (via corepack), Docker.
corepack enable # activates pnpm from package.json's packageManager
pnpm install
cp .env.example .env # dev defaults, no real secrets — then add your
# ANTHROPIC_UPSTREAM_API_KEY (no provider key = no routes)
docker compose up -d # postgres (pgvector) + the three role-split redis
pnpm --filter @gulley/control-api migrate # apply the SQL migrations
pnpm dev # gateway (:8080), control-api (:8081), web (:3000)Every workspace script (dev, migrate, seed, the *:check smoke tests) loads the
repo-root .env itself (--env-file-if-exists), so nothing has to be exported into
the shell; Turborepo's strict env mode is not in the way. The gateway answers /ready
with 503 until at least one provider route is configured and the database schema is
current, so check curl -s localhost:8080/ready before the first request.
Mint a virtual key and point any Anthropic-Messages client at the gateway:
# mint a key (prints a gk_ token once; DATABASE_URL + GULLEY_KEY_PEPPER come from .env)
pnpm --filter @gulley/control-api seed --name dev
export ANTHROPIC_BASE_URL=http://localhost:8080
export ANTHROPIC_API_KEY=gk_... # the printed token
curl -s "$ANTHROPIC_BASE_URL/v1/messages" \
-H "x-api-key: $ANTHROPIC_API_KEY" -H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-haiku-4-5","max_tokens":32,"messages":[{"role":"user","content":"hello"}]}'
# now Claude Code, Codex, or curl all flow through GulleyPrefer short-lived, identity-bound tokens over static keys? Turn on the OAuth broker
(OAUTH_BROKER_ENABLED=true on both apps), register a client in the console, and have
developers run pnpm gulley login — Claude Code and Codex then fetch tokens through
gulley token. See docs/HARNESS_OAUTH.md.
Two release images are published multi-arch (amd64 + arm64), distroless, cosign-signed
with SBOM + SLSA provenance: ghcr.io/bogware/gulley (one image runs either the
gateway or the control-api) and ghcr.io/bogware/gulley-web (the console) —
how to verify. The SQL migrations ship in the API image
(node dist/control-api/migrate.mjs).
- AWS ECS (Terraform) — one adaptable module,
testandprodtiers, with an exact agent/operator runbook:infra/terraform/INSTALL.md. - AWS EKS (Terraform) — the sibling module that stands up the cluster + data tier
for the Helm chart:
infra/eks. - Kubernetes —
deploy/helm/gulley; seedeploy/README.md. - Single host —
deploy/docker-compose.prod.yml(upmigrates the database first, then starts both planes). - Identity — wire Microsoft Entra SSO + SCIM:
docs/ENTRA_SETUP.md; SAML 2.0 SSO:docs/SAML_SETUP.md. - Air-gapped — a no-egress posture:
docs/AIR_GAPPED.md.
| Command | What it does |
|---|---|
pnpm dev |
Run all apps in watch mode (each loads the repo-root .env) |
bash ci/verify.sh |
The full local gate (format/lint/types/test/build/bundle) |
pnpm test |
Unit/integration tests (Vitest) |
pnpm --filter @gulley/<pkg> test |
Test one package |
pnpm --filter @gulley/control-api migrate |
Apply the SQL migrations (same entry the image runs) |
pnpm db:generate |
Generate a SQL migration from the Drizzle schema |
pnpm bundle |
esbuild-bundle both apps into dist/ (what the image runs) |
pnpm --filter @gulley/gateway doctor |
Static preflight over the gateway config |
See CONTRIBUTING.md and our Code of Conduct.
Contributions are accepted under the
Developer Certificate of Origin — sign your commits
with git commit -s. Report vulnerabilities privately via
Security Advisories; see
SECURITY.md.
Apache License 2.0. Copyright 2026 The Gulley Authors.



