mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-07-27 04:31:57 +00:00
docs: unified docs architecture — hub + hanzo-docs/<team> submodule pattern (#29)
* docs: redirect /docs/{startups,deploy} → real pages (QA 404 fix)
getting-started references /docs/startups + /docs/deploy but those slugs 404
(the mdx pages didn't survive an earlier merge). Redirect to the pages that
carry the content: getting-started ($5/startup on-ramp) + services/paas (deploy).
* docs: unified docs architecture — hub + hanzo-docs/<team> submodule pattern
Ratify docs.hanzo.ai as the single unified-build hub and define the one way
content joins it, by kind:
- authored -> content/docs/<section> (in-hub or hanzo-docs/<team> submodule)
- generated -> openapi + ZAP SDK generators, gitignored, never hand-written
- ported -> sync-project-docs mirror + upstream attribution
Changes:
- ADR as a rendered docs page (content/docs/contributing/docs-architecture.mdx)
+ nav entry; LLM.md canonical model + dedup/rollout debt.
- Wire hanzo-docs/studio-docs as the reference exemplar: git submodule at
content/docs/studio/ (was a single tracked file). deploy-docs.yml checkout
now fetches submodules recursively.
- Security: cf-pages-deploy.mjs no longer hard-codes a Cloudflare API token;
it is required from env/KMS and fails fast (token must be rotated).
Standalone-vs-hub criteria, API-ref-from-openapi, and SDK-slot wiring are all
documented in the ADR. Aggregation proven: 38 API-ref pages generated from 36
openapi specs; studio section resolves from the submodule on disk.
---------
Co-authored-by: hanzo-dev <dev@hanzo.ai>
This commit is contained in:
committed by
hanzo-dev
co-authored by
hanzo-dev
parent
cbf29a2672
commit
809d2911e0
@@ -18,6 +18,12 @@ jobs:
|
||||
deployments: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Team-owned doc sections (hanzo-docs/<team>) are mounted as git
|
||||
# submodules under apps/docs/content/docs/. Fetch them so the single
|
||||
# unified build compiles every section. Public HTTPS submodule URLs
|
||||
# need no extra credentials.
|
||||
submodules: recursive
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "apps/docs/content/docs/studio"]
|
||||
path = apps/docs/content/docs/studio
|
||||
url = https://github.com/hanzo-docs/studio-docs.git
|
||||
@@ -2,6 +2,45 @@
|
||||
|
||||
Fork of [Hanzo Docs](https://github.com/hanzoai/docs) with all packages renamed to `@hanzo/docs-*` namespace.
|
||||
|
||||
## Canonical model — the one way to do docs
|
||||
|
||||
Full ADR: `apps/docs/content/docs/contributing/docs-architecture.mdx` (rendered
|
||||
at docs.hanzo.ai/docs/contributing/docs-architecture). Summary:
|
||||
|
||||
- **docs.hanzo.ai is the hub.** ONE Fumadocs build (`apps/docs`) → ONE CF Pages
|
||||
project `hanzo-docs`. The federated per-section deploy is **retired** (stale
|
||||
origins 530'd). Do not reintroduce per-section builds.
|
||||
- **One canonical home per doc.** Content enters the single build via exactly one
|
||||
of three orthogonal mechanisms, chosen by *kind*:
|
||||
1. **Authored** (first-party prose) → MDX under `content/docs/<section>/`.
|
||||
Small/core sections live in-repo; team-owned sections live in a
|
||||
`hanzo-docs/<team>` content repo mounted as a **git submodule** at
|
||||
`content/docs/<team>/`. Exemplar: `hanzo-docs/studio-docs` → `content/docs/studio/`.
|
||||
2. **Generated** (never hand-written, `.gitignore`d) → API reference from
|
||||
`hanzoai/openapi` via `scripts/sync-openapi.sh` + `scripts/gen-openapi-pages.ts`
|
||||
(source-derived: add a service spec, it appears next build); SDK reference
|
||||
from the ZAP SDK generator into `content/docs/sdks/<lang>/`.
|
||||
3. **Ported** (upstream OSS, mirrored with attribution, `.gitignore`d) →
|
||||
`scripts/sync-project-docs.ts` into `content/docs/projects/<upstream>/`.
|
||||
Port, don't re-author. Carry upstream LICENSE + NOTICE. GPL stays GPL.
|
||||
- **Repos:** `hanzo-docs/docs` = framework + hub (canonical; `hanzoai/docs`
|
||||
redirects here). `hanzo-docs/<team>` = authored content only, NO framework.
|
||||
`hanzoai/openapi` = the API source of truth. All docs live in the `hanzo-docs`
|
||||
org: the hub at `hanzo-docs/docs`, each team's content at `hanzo-docs/<team>`.
|
||||
- **Standalone vs hub:** default is a hub section. Standalone deploy only if ALL
|
||||
of: ≈150+ pages or fast OSS-upstream churn, independent versioning, direct
|
||||
audience. Standalone runs its own copy of this framework; the hub links out,
|
||||
never copies.
|
||||
- **Serving:** CF Pages `hanzo-docs` (token from KMS, never hard-coded) or
|
||||
`ghcr.io/hanzoai/docs` behind hanzoai/ingress. No nginx/caddy.
|
||||
|
||||
**Known dedup debt (rollout, not done):** the `apps/*-docs` legacy apps
|
||||
(base-docs, bootnode-docs, bot-docs, cloud, dev-docs, dns-docs, flow, gui-docs,
|
||||
insights-docs, platform, pulsar-docs, spec, tasks-docs, team, visor, zen-docs,
|
||||
zt-docs) predate the unified `content/docs/` model — migrate their content into
|
||||
`content/docs/<section>/` (or a `hanzo-docs/<team>` submodule) then archive the
|
||||
app.
|
||||
|
||||
## Branch Convention
|
||||
|
||||
- **`main`** — Production branch. CF Pages deploys docs.hanzo.ai from here. All Hanzo work lands here.
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
---
|
||||
title: Docs Architecture (ADR)
|
||||
description: The one and only way Hanzo documentation is sourced, built, and joined into docs.hanzo.ai. Hub-and-spoke over a single unified build.
|
||||
icon: Network
|
||||
---
|
||||
|
||||
import { Callout } from '@hanzo/docs-ui/components/callout';
|
||||
|
||||
# Docs Architecture
|
||||
|
||||
**Status:** Accepted · **Scope:** all Hanzo, Lux, Zoo, Zen documentation · **Supersedes:** federated per-section deploys (retired)
|
||||
|
||||
This is the definitive model for how Hanzo docs are sourced, built, and served.
|
||||
One hub, one build, one canonical home per document. If a rule here conflicts
|
||||
with anything you find in a repo, this wins.
|
||||
|
||||
## The decision
|
||||
|
||||
<Callout type="info">
|
||||
**docs.hanzo.ai is the hub.** It is a single [Fumadocs](https://fumadocs.dev)
|
||||
build (`apps/docs` in `hanzoai/docs`) compiled in one pass and deployed to a
|
||||
single Cloudflare Pages project (`hanzo-docs`). Every doc renders here unless it
|
||||
qualifies for a standalone site, in which case the hub links out — it never
|
||||
copies.
|
||||
</Callout>
|
||||
|
||||
Three things follow from "one and only one way":
|
||||
|
||||
1. **One build.** All content — core guides, every service, every ported OSS
|
||||
project — compiles in the single `apps/docs` pass. The previous federated
|
||||
layout (one Pages project per section, stitched by an edge worker) is
|
||||
**retired**: stale `*.pages.dev` origins 530'd whole sections. Do not
|
||||
reintroduce per-section deploys.
|
||||
2. **One canonical home per doc.** Every page has exactly one source of truth.
|
||||
No page is authored in two places. Duplication is a bug.
|
||||
3. **One join mechanism per source *kind*.** How content enters the build is
|
||||
determined by *what kind of content it is* — authored, generated, or ported —
|
||||
not by who owns it. Three kinds, three orthogonal mechanisms (below).
|
||||
|
||||
## Repositories
|
||||
|
||||
| Repo | Holds | Never holds |
|
||||
|------|-------|-------------|
|
||||
| **`hanzo-docs/docs`** | The framework (`@hanzo/docs-*` packages) **and** the hub app (`apps/docs`). Canonical — `hanzoai/docs` redirects here. | Team-owned content that wants its own release cadence. |
|
||||
| **`hanzo-docs/<team>`** | *Authored* content only — MDX + `meta.json` + `LICENSE`/`NOTICE`. No framework, no build config. | Any Next.js/Fumadocs wiring. It is content, not a site. |
|
||||
| **`hanzoai/openapi`** | The OpenAPI 3.1 spec for every service. Source of truth for **all** API reference. | Hand-written prose reference. |
|
||||
|
||||
All docs live in the **`hanzo-docs`** org: the hub + framework at
|
||||
`hanzo-docs/docs`, each team's content at `hanzo-docs/<team>`. The API source of
|
||||
truth stays with the code, at `hanzoai/openapi`. A `hanzo-docs/<team>` repo (any
|
||||
but `docs`) that carries a framework `package.json` has drifted — fix it.
|
||||
|
||||
## The three content mechanisms
|
||||
|
||||
Content enters the unified build through exactly one of three paths, chosen by
|
||||
kind. They are orthogonal: a change to one never touches another.
|
||||
|
||||
### 1. Authored — first-party content we write
|
||||
|
||||
Prose guides, concepts, tutorials. Lives as MDX under `content/docs/`.
|
||||
|
||||
- **Small / core sections** live directly in `hanzoai/docs` at
|
||||
`apps/docs/content/docs/<section>/`. No repo sprawl for a handful of pages.
|
||||
- **Team-owned sections** live in their own `hanzo-docs/<team>` repo and are
|
||||
mounted into the hub as a **git submodule** at
|
||||
`apps/docs/content/docs/<team>/`. The hub pins a commit; the team owns the
|
||||
content. The build globs `content/docs/**/*.mdx` and neither knows nor cares
|
||||
that a directory is a submodule — the join is pure git, zero build code.
|
||||
|
||||
Choose a submodule when a team needs its own release cadence, external
|
||||
contributors, or a large surface. Otherwise keep it in-hub. `hanzo-docs/studio-docs`
|
||||
mounted at `content/docs/studio/` is the reference exemplar.
|
||||
|
||||
### 2. Generated — never hand-written
|
||||
|
||||
API reference and SDK reference are **generated** from a machine-readable source
|
||||
and are `.gitignore`d build artifacts. Editing a generated page is forbidden;
|
||||
edit the source.
|
||||
|
||||
- **API reference** ← `hanzoai/openapi`. `scripts/sync-openapi.sh` copies every
|
||||
`<service>/openapi.yaml` into `openapi-specs/` (source-derived — no hardcoded
|
||||
service list; adding a service to `hanzoai/openapi` makes it appear on the
|
||||
next build). `scripts/gen-openapi-pages.ts` renders one static MDX page per
|
||||
spec into `content/docs/openapi/<service>.mdx`, cross-linked to the matching
|
||||
prose guide. **38 reference pages from 36 specs today, zero hand-authored.**
|
||||
- **SDK reference** ← the ZAP SDK generator (per language). Generated MDX lands
|
||||
in `content/docs/sdks/<lang>/`. The slot exists (`python`, `typescript`, `go`,
|
||||
`rust`, `c`); the generator writes into it. Do not hand-author SDK method
|
||||
tables — regenerate them.
|
||||
|
||||
### 3. Ported — upstream OSS docs, mirrored with attribution
|
||||
|
||||
For forks (Studio←ComfyUI, Engine←mistral.rs, Flow←Langflow, …) we **port, we do
|
||||
not re-author**. `scripts/sync-project-docs.ts` mirrors upstream docs into
|
||||
`content/docs/projects/<upstream>/` (source-derived from the GitHub orgs;
|
||||
`.gitignore`d). Foreign JSX (Mintlify/Docusaurus/GitBook components) is
|
||||
neutralised so a single build stays safe. Every ported tree carries the
|
||||
upstream `LICENSE` and a `NOTICE` crediting the source. Respect the upstream
|
||||
license — GPL content stays GPL; attribution is not optional.
|
||||
|
||||
<Callout type="warn">
|
||||
Authored vs ported is the sharpest line. `hanzo-docs/studio-docs` holds
|
||||
*our* Studio guides (first-party). The wholesale ComfyUI manual is *ported*
|
||||
into `content/docs/projects/comfyui/`. They never mix.
|
||||
</Callout>
|
||||
|
||||
## Hub section vs standalone site
|
||||
|
||||
Default is a hub section. A product earns a **standalone** deploy only when **all
|
||||
three** hold:
|
||||
|
||||
1. **Large** — the surface is big enough that co-building it in the hub hurts
|
||||
build time (≈150+ pages), **or** it tracks a fast-moving OSS upstream.
|
||||
2. **Independently versioned** — it ships docs on its own cadence, decoupled from
|
||||
the platform.
|
||||
3. **Direct audience** — users land on it directly, not via the platform hub.
|
||||
|
||||
When a product goes standalone it runs its **own copy of this same framework**
|
||||
(`@hanzo/create-docs`), and the hub shows a card that **links out**. The content
|
||||
still has exactly one home; it is **not** also aggregated into the hub. No
|
||||
duplication, ever. Everything else is a hub section.
|
||||
|
||||
## Serving
|
||||
|
||||
- **Primary:** static export → Cloudflare Pages project `hanzo-docs`
|
||||
(`scripts/cf-pages-deploy.mjs`). The deploy token comes from KMS
|
||||
(`kms.hanzo.ai`) at run time — never hard-coded.
|
||||
- **In-cluster option:** `ghcr.io/hanzoai/docs` behind **hanzoai/ingress**
|
||||
(`k8s/docs-landing.yml`). No nginx, no caddy — the Hanzo ingress + static
|
||||
plugin only.
|
||||
|
||||
White-label by hostname via `@hanzo/docs-org` presets (Hanzo / Lux / Zoo / Zen).
|
||||
One framework, four brands, resolved at request time.
|
||||
|
||||
## Adding docs — the decision in one paragraph
|
||||
|
||||
Writing a guide for an existing product? Add MDX under its
|
||||
`content/docs/<section>/` (or its `hanzo-docs/<team>` submodule). Documenting an
|
||||
API? Don't — update `hanzoai/openapi` and it regenerates. Documenting an SDK?
|
||||
Don't — the ZAP generator emits it. Bringing a fork's upstream manual? Add the
|
||||
repo to `sync-project-docs` config; it mirrors with attribution. Nothing else is
|
||||
a supported way to add docs.
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"title": "Contributing",
|
||||
"description": "How Hanzo docs are built, sourced, and joined into docs.hanzo.ai",
|
||||
"icon": "GitPullRequest",
|
||||
"pages": ["docs-architecture"]
|
||||
}
|
||||
@@ -86,6 +86,8 @@
|
||||
"---Research---",
|
||||
"research",
|
||||
"---Open Source---",
|
||||
"projects"
|
||||
"projects",
|
||||
"---Contributing---",
|
||||
"contributing"
|
||||
]
|
||||
}
|
||||
|
||||
Submodule
+1
Submodule apps/docs/content/docs/studio added at c17c4b8687
@@ -1,243 +0,0 @@
|
||||
---
|
||||
title: Hanzo Studio
|
||||
description: Visual AI engine for building image, video, 3D, and audio workflows. Node-based editor with GPU scaling, multi-tenant isolation, and enterprise billing.
|
||||
index: true
|
||||
---
|
||||
|
||||
import { Card, Cards } from '@hanzo/docs-base-ui/components/card';
|
||||
|
||||
# Hanzo Studio
|
||||
|
||||
Visual AI engine for production workflows. Build **image generation**, **video synthesis**, **3D rendering**, and **audio processing** pipelines with a drag-and-drop node editor -- then scale to GPU when you need real throughput.
|
||||
|
||||
Available at [studio.hanzo.ai](https://studio.hanzo.ai) or self-hosted via Docker. Built on [ComfyUI](https://github.com/comfyanonymous/ComfyUI) with full node compatibility.
|
||||
|
||||
```bash title="Quick Start"
|
||||
docker pull ghcr.io/hanzoai/studio:latest
|
||||
docker run -p 8188:8188 ghcr.io/hanzoai/studio:latest \
|
||||
python main.py --listen 0.0.0.0 --cpu
|
||||
# Open http://localhost:8188
|
||||
```
|
||||
|
||||
## Why Hanzo Studio?
|
||||
|
||||
- **Visual Node Editor** -- Wire together models, preprocessors, and outputs in a graph-based canvas. Every node is composable.
|
||||
- **GPU on Demand** -- Start on CPU for prototyping. Switch to T4, A100, or H100 with one API call when you're ready for production.
|
||||
- **Distributed Workers** -- Route GPU-heavy prompts to dedicated worker machines. The coordinator handles queuing, routing, and result aggregation.
|
||||
- **Multi-Tenant Isolation** -- Each organization gets isolated storage, compute profiles, and usage tracking. IAM authentication via [hanzo.id](https://hanzo.id).
|
||||
- **Usage Billing** -- Metered billing per prompt execution via Hanzo Commerce. Per-second pricing, minimum 1 credit per run.
|
||||
- **Full ComfyUI Compatibility** -- Every custom node, model, and workflow from the ComfyUI ecosystem works out of the box. No vendor lock-in.
|
||||
|
||||
## Compute Profiles
|
||||
|
||||
Each organization gets a compute profile that determines how prompts are executed. Switch profiles at any time via the API.
|
||||
|
||||
| Profile | Device | GPU | VRAM | Best For |
|
||||
|---------|--------|-----|------|----------|
|
||||
| `cpu` | CPU | -- | -- | Prototyping, lightweight workflows |
|
||||
| `gpu-basic` | CUDA | T4 | 16 GB | Image generation, standard diffusion models |
|
||||
| `gpu-pro` | CUDA | A100 | 80 GB | Large models, video generation, 3D |
|
||||
| `gpu-max` | CUDA | H100 | 80 GB | Maximum throughput, batch processing |
|
||||
| `custom` | CUDA | Any | Any | Bring your own instance type |
|
||||
|
||||
### Switch to GPU
|
||||
|
||||
```bash
|
||||
curl -X PUT https://studio.hanzo.ai/api/compute/config \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"active_profile": "gpu-basic",
|
||||
"gpu_type": "t4",
|
||||
"auto_provision": true
|
||||
}'
|
||||
```
|
||||
|
||||
When `auto_provision` is enabled, Studio automatically launches a GPU VM through [Visor](https://visor.hanzo.ai) on first GPU prompt. The worker registers itself within 60 seconds and begins accepting work.
|
||||
|
||||
```bash title="Check Current Config"
|
||||
curl https://studio.hanzo.ai/api/compute/config \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN"
|
||||
```
|
||||
|
||||
## GPU Workers
|
||||
|
||||
Studio supports distributed execution via **worker mode**. A coordinator (the main Studio instance) routes prompts to GPU workers based on the active compute profile.
|
||||
|
||||
### How It Works
|
||||
|
||||
```
|
||||
Client ──prompt──▸ Coordinator (studio.hanzo.ai)
|
||||
│
|
||||
├── CPU prompt ──▸ local execution
|
||||
├── GPU prompt ──▸ Worker 1 (T4, 16GB)
|
||||
└── GPU prompt ──▸ Worker 2 (A100, 80GB)
|
||||
```
|
||||
|
||||
1. Client submits a prompt with optional `device_preference`
|
||||
2. Coordinator checks the org's compute profile
|
||||
3. If GPU requested, the prompt is forwarded to an available GPU worker via HTTP
|
||||
4. Worker executes locally, returns the result
|
||||
5. Coordinator forwards the result back to the client WebSocket
|
||||
|
||||
### Launch a GPU Worker
|
||||
|
||||
```bash
|
||||
curl -X POST https://studio.hanzo.ai/api/compute/provision \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"gpu_type": "t4",
|
||||
"worker_id": "my-gpu-worker"
|
||||
}'
|
||||
```
|
||||
|
||||
Workers auto-register with the coordinator via heartbeats every 30 seconds. Stale workers (no heartbeat for 90s) are removed from the pool.
|
||||
|
||||
### Self-Hosted Workers
|
||||
|
||||
Run a Studio instance as a headless GPU worker that registers with your coordinator:
|
||||
|
||||
```bash
|
||||
docker run --gpus all -p 8188:8188 \
|
||||
ghcr.io/hanzoai/studio:latest \
|
||||
python main.py \
|
||||
--listen 0.0.0.0 \
|
||||
--worker-mode \
|
||||
--coordinator-url http://your-coordinator:8188 \
|
||||
--worker-id gpu-worker-1
|
||||
```
|
||||
|
||||
### List Workers
|
||||
|
||||
```bash
|
||||
curl https://studio.hanzo.ai/api/compute/workers \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN"
|
||||
```
|
||||
|
||||
Returns status, device info, VRAM, and last heartbeat for each registered worker.
|
||||
|
||||
## Prompt Routing
|
||||
|
||||
Control where prompts execute with the `device_preference` field:
|
||||
|
||||
```bash
|
||||
curl -X POST https://studio.hanzo.ai/api/prompt \
|
||||
-H "Authorization: Bearer $HANZO_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"prompt": { ... },
|
||||
"device_preference": "gpu"
|
||||
}'
|
||||
```
|
||||
|
||||
| Preference | Behavior |
|
||||
|------------|----------|
|
||||
| `auto` (default) | GPU if enabled in profile and worker available, else CPU |
|
||||
| `cpu` | Always execute locally on CPU |
|
||||
| `gpu` | Route to GPU worker. Returns 503 if none available |
|
||||
|
||||
When `auto_provision` is enabled and no GPU worker is available, Studio returns `202 Accepted` and begins provisioning. Poll the workers endpoint for status.
|
||||
|
||||
## API Reference
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `POST` | `/api/prompt` | Submit a workflow prompt |
|
||||
| `GET` | `/api/queue` | Queue status and pending jobs |
|
||||
| `GET` | `/api/jobs` | List jobs with filtering |
|
||||
| `GET` | `/api/system_stats` | Device info, memory, VRAM |
|
||||
| `GET` | `/api/compute/config` | Get org compute profile |
|
||||
| `PUT` | `/api/compute/config` | Update compute profile |
|
||||
| `GET` | `/api/compute/workers` | List registered workers |
|
||||
| `POST` | `/api/compute/workers/register` | Worker heartbeat (internal) |
|
||||
| `POST` | `/api/compute/provision` | Launch GPU VM via Visor |
|
||||
| `DELETE` | `/api/compute/provision` | Terminate GPU VM |
|
||||
|
||||
## Self-Hosted Deployment
|
||||
|
||||
### CPU Only
|
||||
|
||||
```bash
|
||||
docker run -d --name studio \
|
||||
-p 8188:8188 \
|
||||
-v studio-data:/app/user \
|
||||
ghcr.io/hanzoai/studio:latest \
|
||||
python main.py --listen 0.0.0.0 --cpu
|
||||
```
|
||||
|
||||
### GPU (NVIDIA)
|
||||
|
||||
```bash
|
||||
docker run -d --name studio --gpus all \
|
||||
-p 8188:8188 \
|
||||
-v studio-data:/app/user \
|
||||
ghcr.io/hanzoai/studio:latest \
|
||||
python main.py --listen 0.0.0.0
|
||||
```
|
||||
|
||||
### With IAM Auth + Billing
|
||||
|
||||
```yaml title="compose.yml"
|
||||
services:
|
||||
studio:
|
||||
image: ghcr.io/hanzoai/studio:latest
|
||||
ports:
|
||||
- "8188:8188"
|
||||
environment:
|
||||
STUDIO_ENABLE_IAM_AUTH: "true"
|
||||
STUDIO_IAM_URL: "https://hanzo.id"
|
||||
STUDIO_NO_LOCALHOST_BYPASS: "true"
|
||||
STUDIO_MULTI_TENANT: "true"
|
||||
STUDIO_ORG_ID: "my-org"
|
||||
STUDIO_ENABLE_BILLING: "true"
|
||||
STUDIO_COMMERCE_URL: "http://commerce.hanzo.svc:8001"
|
||||
STUDIO_COMMERCE_TOKEN: "${COMMERCE_TOKEN}"
|
||||
volumes:
|
||||
- studio-data:/app/user
|
||||
command: ["python", "main.py", "--listen", "0.0.0.0", "--cpu"]
|
||||
|
||||
volumes:
|
||||
studio-data:
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `STUDIO_ENABLE_IAM_AUTH` | `false` | Enable IAM authentication via hanzo.id |
|
||||
| `STUDIO_IAM_URL` | `https://hanzo.id` | IAM server URL |
|
||||
| `STUDIO_NO_LOCALHOST_BYPASS` | `false` | Require auth even for localhost |
|
||||
| `STUDIO_MULTI_TENANT` | `false` | Per-org storage isolation |
|
||||
| `STUDIO_ORG_ID` | -- | Default organization ID |
|
||||
| `STUDIO_ENABLE_BILLING` | `false` | Enable Commerce usage billing |
|
||||
| `STUDIO_COMMERCE_URL` | `http://commerce.hanzo.svc:8001` | Commerce API endpoint |
|
||||
| `STUDIO_RATE_LIMIT_RPM` | `60` | Max prompts per minute per org |
|
||||
| `STUDIO_ENABLE_METRICS` | `false` | Enable Prometheus `/metrics` endpoint |
|
||||
| `STUDIO_WORKER_MODE` | `false` | Run as headless GPU worker |
|
||||
| `COORDINATOR_URL` | -- | Coordinator URL (worker mode only) |
|
||||
| `WORKER_ID` | -- | Unique worker identifier |
|
||||
| `VISOR_URL` | `https://visor.hanzo.ai` | Visor API for GPU provisioning |
|
||||
|
||||
## Get Started
|
||||
|
||||
1. Sign in at [studio.hanzo.ai](https://studio.hanzo.ai) with your Hanzo account
|
||||
2. Build a workflow in the visual node editor
|
||||
3. Submit prompts -- runs on CPU by default
|
||||
4. When you need GPU, call `PUT /api/compute/config` to switch profiles
|
||||
5. Studio provisions GPU workers automatically and routes your prompts
|
||||
|
||||
<Cards>
|
||||
<Card title="Hanzo Chat" href="/docs/chat">
|
||||
AI chat with Zen models, MCP and ZAP tools
|
||||
</Card>
|
||||
<Card title="LLM Gateway" href="/docs/llm">
|
||||
Unified API proxy for 200+ language models
|
||||
</Card>
|
||||
<Card title="MCP Tools" href="/docs/mcp">
|
||||
Model Context Protocol tool integrations
|
||||
</Card>
|
||||
<Card title="API Reference" href="/docs/openapi">
|
||||
Full OpenAPI specification for all services
|
||||
</Card>
|
||||
</Cards>
|
||||
@@ -7,9 +7,18 @@ import { createHash } from 'crypto';
|
||||
import { readdir, readFile, stat } from 'fs/promises';
|
||||
import { join, relative } from 'path';
|
||||
|
||||
const ACCOUNT_ID = '94a3e3f299092abb1feda2a7481ea845';
|
||||
const PROJECT_NAME = 'hanzo-docs';
|
||||
const API_TOKEN = process.env.CLOUDFLARE_API_TOKEN || 'bBEtGaPXpGSmvC5w2WbpE2V7zx08VDWspCS-E30g';
|
||||
const ACCOUNT_ID = process.env.CLOUDFLARE_ACCOUNT_ID || '94a3e3f299092abb1feda2a7481ea845';
|
||||
const PROJECT_NAME = process.env.CF_PAGES_PROJECT || 'hanzo-docs';
|
||||
// Never hard-code the token. CI injects CLOUDFLARE_API_TOKEN from KMS
|
||||
// (kms.hanzo.ai → the docs deploy service account). Fail fast if absent.
|
||||
const API_TOKEN = process.env.CLOUDFLARE_API_TOKEN;
|
||||
if (!API_TOKEN) {
|
||||
console.error(
|
||||
'CLOUDFLARE_API_TOKEN is required. It is provisioned from KMS (kms.hanzo.ai) in CI; ' +
|
||||
'for a local deploy export it from your KMS session. Refusing to run without it.',
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
const BASE_URL = `https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/pages/projects/${PROJECT_NAME}`;
|
||||
const BATCH_SIZE = 50; // files per upload batch
|
||||
const MAX_RETRIES = 3;
|
||||
|
||||
Reference in New Issue
Block a user