From eeaa392c5e0d0647ac0af1d2e4b84321ecbfbb35 Mon Sep 17 00:00:00 2001 From: khushalsonawat Date: Fri, 26 Jun 2026 13:12:41 +0530 Subject: [PATCH 01/24] docs(self-hosting): rewrite the overview as an explanation page - Lean what/when/architecture overview that routes setup detail to the Configure subfolder - Keep the architecture diagram and the deployment-options table --- src/pages/docs/self-hosting.mdx | 105 ++++++++++---------------------- 1 file changed, 32 insertions(+), 73 deletions(-) diff --git a/src/pages/docs/self-hosting.mdx b/src/pages/docs/self-hosting.mdx index dd3c9fbf..e2dd80c7 100644 --- a/src/pages/docs/self-hosting.mdx +++ b/src/pages/docs/self-hosting.mdx @@ -1,49 +1,28 @@ --- -title: "Self-Hosting Future AGI: Deploy on Your Own Infrastructure" -description: "Deploy the full Future AGI platform on your own infrastructure using Docker Compose. Follow the step-by-step guide to get all services running locally." +title: "Self-hosting Future AGI" +description: "Run the entire Future AGI platform on your own infrastructure with Docker Compose. Your traces, datasets, evaluations, and model calls stay inside your network" --- -## About +Future AGI is fully open-source. Self-hosting runs the **entire stack on your own machines**, so all traces, datasets, evaluations, and model calls stay within your network. The backend is Django, the frontend is React + Vite, and the LLM gateway is Go, all deployed together with Docker Compose -Future AGI is fully open-source. Self-hosting runs the entire stack on your machines — all traces, datasets, evaluations, and model calls stay within your network. Backend is Django, frontend is React + Vite, LLM gateway is Go. +## When to self-host -Not sure if you need this? The hosted version at [app.futureagi.com](https://app.futureagi.com) is easier to operate. Self-host when you need **data residency**, **air-gapped environments**, **cost control at scale**, or **deep customization**. +The [**cloud hosted version**](https://app.futureagi.com) is the easiest way to run Future AGI, with nothing to operate. Self-host when you need: -## Quick start +- **Data residency**: keep all data inside your own network +- **Air-gapped environments**: run with no outbound dependencies +- **Cost control at scale**: own the infrastructure +- **Deep customization**: modify the open-source stack to fit your needs -```bash -git clone https://github.com/future-agi/future-agi.git -cd future-agi -cp .env.example .env -docker pull futureagi/future-agi:v1.8.19_base -docker compose up -``` - -First boot builds from source (~10–15 min). After `Application startup complete`: - -| Service | URL | -|---|---| -| Frontend | http://localhost:3000 | -| Backend API | http://localhost:8000 | -| PeerDB UI | http://localhost:3001 — `peerdb` / `peerdb` | - -## Deployment options - -| Option | Status | -|---|---| -| Docker Compose | Available | -| Helm / Kubernetes | Coming soon | -| Air-gapped | Coming soon | +## What you deploy -## Architecture - -21 containers across four layers. +Self-hosting brings up the full platform (around **21 containers, with no external dependencies**) across four layers: ``` Browser └─ frontend (React/nginx) - └─ backend (Django) ──── gateway (Go) ──── OpenAI · Anthropic · Gemini · Bedrock - ├── postgres primary DB + WAL replication + └─ backend (Django) ──── gateway (Go) ──── OpenAI · Anthropic · Gemini · Bedrock + ├── postgres primary database ├── clickhouse analytics store ├── redis cache / pub-sub ├── minio object storage @@ -52,51 +31,31 @@ Browser postgres ──── PeerDB CDC ──── clickhouse (continuous replication) ``` -**Application** — `frontend` · `backend` · `worker` · `gateway` · `serving` · `code-executor` - -**Data** — `postgres` · `clickhouse` · `redis` · `minio` +- **Application**: `frontend`, `backend`, `worker`, `gateway`, `serving`, `code-executor` +- **Data**: `postgres`, `clickhouse`, `redis`, `minio` +- **Workflow**: `temporal` +- **CDC**: PeerDB (continuous Postgres → ClickHouse replication) -**Workflow** — `temporal` +Everything runs on your machines; nothing leaves your network. The full service-by-service breakdown lives in [Configure](/docs/self-hosting/configure) -**CDC (PeerDB)** — `peerdb-catalog` · `peerdb-temporal` · `peerdb-minio` · `peerdb-flow-api` · `peerdb-flow-worker` · `peerdb-flow-snapshot-worker` · `peerdb-server` · `peerdb-ui` · `peerdb-temporal-init` · `peerdb-init` +## Deployment options -| Layer | Service | Purpose | -|---|---|---| -| App | `frontend` | React SPA served by nginx | -| App | `backend` | Django REST + gRPC + WebSocket API | -| App | `worker` | Temporal worker — evals, agent loops, data jobs | -| App | `gateway` | Go LLM proxy — routing, retries, rate limits, logging | -| App | `serving` | Embeddings and small model inference | -| App | `code-executor` | nsjail-sandboxed eval code runner (`privileged: true` required) | -| Data | `postgres` | Primary DB — users, traces, datasets, evals, prompts | -| Data | `clickhouse` | Analytics DB — replicated from Postgres via PeerDB | -| Data | `redis` | Cache, rate limits, WebSocket pub/sub | -| Data | `minio` | S3-compatible object storage (swap for S3 in prod) | -| Workflow | `temporal` | Durable workflow engine — shares main Postgres | -| CDC | PeerDB stack | Continuous Postgres → ClickHouse replication (10 services) | +| Option | Status | +|---|---| +| Docker Compose | Available | +| Helm / Kubernetes | Coming soon | +| Air-gapped | Coming soon | -## Next Steps +## Where to go next - - - Hardware tiers, platform compatibility, ports reference. - - - Setup, deployment modes, day-to-day operations. - - - Full `.env` reference — secrets, ports, flags, keys. - - - LLM gateway providers, PeerDB mirrors, Temporal workers. - - - Create accounts via email or Django shell. + + + System requirements, prerequisites, environment variables, and setup - - Hardening, backups, monitoring, upgrades. + + Fixes for common errors and answers to frequent questions - - Solutions for every known error. + + Get help from the Future AGI team and community From f427b0994774847dddb12b724f9a204d9cbda4c5 Mon Sep 17 00:00:00 2001 From: khushalsonawat Date: Mon, 29 Jun 2026 16:34:30 +0530 Subject: [PATCH 02/24] feat(docs): reorder product dropdown by agent lifecycle Reorder the Docs section-switcher dropdown from alphabetical to agent-development-lifecycle order, grouped under lightweight phase headers (Start, Observe & diagnose, Evaluate & measure, Improve, Build & connect, Protect, Assistant, Reference). "Resources" is omitted and "Falcon AI" sits last. The change lands on the live dropdown in Sidebar.astro (Docs tab only; other tabs fall back to a single unlabelled list). A "More" bucket surfaces any future product that isn't placed, so nothing silently disappears. Remove the dead SectionSwitcher.astro and Breadcrumb.astro components: nothing rendered them (DocsLayout uses its own inline breadcrumb), and the build of all 931 pages passes without them. --- src/components/Breadcrumb.astro | 55 ------- src/components/SectionSwitcher.astro | 210 --------------------------- src/components/Sidebar.astro | 104 ++++++++++--- 3 files changed, 84 insertions(+), 285 deletions(-) delete mode 100644 src/components/Breadcrumb.astro delete mode 100644 src/components/SectionSwitcher.astro diff --git a/src/components/Breadcrumb.astro b/src/components/Breadcrumb.astro deleted file mode 100644 index 8b90bb7d..00000000 --- a/src/components/Breadcrumb.astro +++ /dev/null @@ -1,55 +0,0 @@ ---- -import SectionSwitcher from './SectionSwitcher.astro'; - -const currentPath = Astro.url.pathname; -const pathParts = currentPath.split('/').filter(Boolean); - -function toTitleCase(str: string) { - return str - .split('-') - .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) - .join(' '); -} - -// Skip 'docs' from breadcrumb display since we show it via the section switcher -const breadcrumbParts = pathParts.filter(part => part !== 'docs'); -const breadcrumbs = breadcrumbParts.map((part, index) => { - // Build href from the original path parts - const originalIndex = pathParts.indexOf(part); - return { - label: toTitleCase(part), - href: '/' + pathParts.slice(0, originalIndex + 1).join('/'), - isLast: index === breadcrumbParts.length - 1, - }; -}); - -// Only show crumbs after the first one (which is shown in the section switcher) -const trailCrumbs = breadcrumbs.slice(1); ---- - - diff --git a/src/components/SectionSwitcher.astro b/src/components/SectionSwitcher.astro deleted file mode 100644 index 80bba85a..00000000 --- a/src/components/SectionSwitcher.astro +++ /dev/null @@ -1,210 +0,0 @@ ---- -/** - * Section Switcher Dropdown - * PostHog-style dropdown for switching between documentation sections. - * Shows the current section with an icon and lets users jump to any other section. - */ -import { tabNavigation, type NavTab } from '../lib/navigation'; - -const currentPath = Astro.url.pathname; - -// All navigable sections from the Docs tab -const docsTab = tabNavigation.find(t => t.tab === 'Docs'); -const sections = docsTab?.groups || []; - -// Find the current section based on URL -function getCurrentSection() { - // Check specific tabs first - for (const tab of tabNavigation) { - if (tab.href !== '/docs' && currentPath.startsWith(tab.href)) { - return { title: tab.tab, icon: tab.icon, href: tab.href }; - } - } - - // Check within docs groups - for (const group of sections) { - for (const item of group.items) { - if (item.href && (currentPath === item.href || currentPath.startsWith(item.href + '/'))) { - return { title: group.group, icon: group.icon || 'default', href: item.href }; - } - if (item.items) { - for (const child of item.items) { - if (child.href && (currentPath === child.href || currentPath.startsWith(child.href + '/'))) { - return { title: group.group, icon: group.icon || 'default', href: item.href || child.href }; - } - } - } - } - } - - return { title: 'Docs', icon: 'book', href: '/docs' }; -} - -const current = getCurrentSection(); - -// Build dropdown items from all sections + tabs -interface DropdownItem { - title: string; - icon: string; - href: string; - description?: string; -} - -const dropdownItems: DropdownItem[] = [ - ...sections.map(g => ({ - title: g.group, - icon: g.icon || 'default', - href: g.items[0]?.href || '/docs', - description: '', - })), - // Add other tabs - { title: 'Integrations', icon: 'plug', href: '/docs/integrations', description: '' }, - { title: 'Guides', icon: 'book', href: '/docs/cookbook', description: '' }, - { title: 'SDK Reference', icon: 'code', href: '/docs/sdk', description: '' }, - { title: 'API Reference', icon: 'webhook', href: '/docs/api', description: '' }, -]; - -const iconPaths: Record = { - 'rocket': 'M13 10V3L4 14h7v7l9-11h-7z', - 'table': 'M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z', - 'play': 'M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z M21 12a9 9 0 11-18 0 9 9 0 0118 0z', - 'chart': 'M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z', - 'zap': 'M13 10V3L4 14h7v7l9-11h-7z', - 'flask': 'M9 3v2m6-2v2M9 19h6m-3-11V3M5 21h14a2 2 0 002-2v-4a2 2 0 00-.586-1.414l-5-5A2 2 0 0014 8V3a1 1 0 00-1-1h-2a1 1 0 00-1 1v5a2 2 0 01-.586 1.414l-5 5A2 2 0 004 15v4a2 2 0 002 2z', - 'eye': 'M15 12a3 3 0 11-6 0 3 3 0 016 0z M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z', - 'compass': 'M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9', - 'gauge': 'M13 7h8m0 0v8m0-8l-8 8-4-4-6 6', - 'shield': 'M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z', - 'brain': 'M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z', - 'plug': 'M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1', - 'book': 'M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253', - 'code': 'M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4', - 'webhook': 'M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4', - 'default': 'M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z', -}; - -function getIconPath(icon: string): string { - return iconPaths[icon] || iconPaths.default; -} ---- - -
- - - - - -
- - diff --git a/src/components/Sidebar.astro b/src/components/Sidebar.astro index be417906..2df4e379 100644 --- a/src/components/Sidebar.astro +++ b/src/components/Sidebar.astro @@ -89,6 +89,62 @@ function getIconPath(icon?: string): string { return iconPaths[icon || 'default'] || iconPaths.default; } +// ── Lifecycle-ordered product dropdown (Docs tab only) ────────────────────── +// Reorders the Docs section dropdown from alphabetical to agent-development- +// lifecycle order, grouped under lightweight phase headers. This is dropdown-only +// and does NOT reorder the `groups` array in navigation.ts, so the page list below +// still follows nav order. "Resources" is intentionally omitted; "Falcon AI" sits +// last; a "Reference" group links out to the Integrations/Guides/SDK/API tabs. +// The dropdown only renders when a tab exposes multiple groups (today that's the +// Docs tab); any other multi-group tab falls back to a single unlabelled list. +interface DropdownItem { title: string; icon: string; href: string; } +interface DropdownSection { phase: string; items: DropdownItem[]; } + +const groupLookup = new Map( + allGroups.map(g => [g.group, { icon: g.icon || 'default', href: g.items[0]?.href || '/docs' }]) +); +// Single source for turning a group title into a dropdown item. +const toItem = (title: string): DropdownItem => { + const g = groupLookup.get(title); + return { title, icon: g?.icon || 'default', href: g?.href || '/docs' }; +}; + +const phasedOrder: { phase: string; titles: string[] }[] = [ + { phase: 'Start', titles: ['Get Started'] }, + { phase: 'Observe & diagnose', titles: ['Observability', 'Error Feed'] }, + { phase: 'Evaluate & measure', titles: ['Evaluation', 'Simulation', 'Dataset'] }, + { phase: 'Improve', titles: ['Optimization', 'Annotations'] }, + { phase: 'Build & connect', titles: ['Prompt', 'Prototype', 'Agent Playground', 'Knowledge Base', 'Agent Command Center'] }, + { phase: 'Protect', titles: ['Protect'] }, + { phase: 'Assistant', titles: ['Falcon AI'] }, +]; + +// Reference links live in their own top-level tabs; surface them at the bottom. +const referenceItems: DropdownItem[] = [ + { title: 'Integrations', icon: 'plug', href: '/docs/integrations' }, + { title: 'Guides', icon: 'book', href: '/docs/cookbook' }, + { title: 'SDK Reference', icon: 'code', href: '/docs/sdk' }, + { title: 'API Reference', icon: 'webhook', href: '/docs/api' }, +]; + +let dropdownSections: DropdownSection[]; +if (isDocsTab) { + dropdownSections = phasedOrder + .map(p => ({ phase: p.phase, items: p.titles.filter(t => groupLookup.has(t)).map(toItem) })) + .filter(s => s.items.length > 0); + + // Future-proofing: surface any Docs group not placed above (besides the hidden + // "Resources") under "More" so new products never silently vanish. + const placed = new Set([...phasedOrder.flatMap(p => p.titles), 'Resources']); + const leftovers = allGroups.map(g => g.group).filter(t => !placed.has(t)).map(toItem); + if (leftovers.length) dropdownSections.push({ phase: 'More', items: leftovers }); + + dropdownSections.push({ phase: 'Reference', items: referenceItems }); +} else { + // Other multi-group tabs: one unlabelled section (empty phase hides the header). + dropdownSections = [{ phase: '', items: allGroups.map(g => toItem(g.group)) }]; +} + // Infer HTTP method from API endpoint title for sidebar badges const isApiTab = activeTab?.tab === 'API'; @@ -139,26 +195,34 @@ function inferApiMethod(title: string): { method: string; css: string } | null { class="absolute left-3 right-3 mt-1 py-1 bg-[var(--color-bg-secondary)] border border-[var(--color-border-default)] rounded-xl shadow-xl shadow-black/20 z-50 hidden opacity-0 transition-all duration-150 max-h-[60vh] overflow-y-auto hide-scrollbar" data-section-dropdown > - {allGroups.map((group) => { - const isCurrent = group.group === activeGroup?.group; - const firstHref = group.items[0]?.href || '/docs'; - return ( - - - - - {group.group} - - ); - })} + {dropdownSections.map((section, sectionIndex) => ( +
0 && "mt-1.5 pt-1.5 border-t border-[var(--color-border-default)]/60"]}> + {section.phase && ( +
+ {section.phase} +
+ )} + {section.items.map((item) => { + const isCurrent = item.title === activeGroup?.group; + return ( + + + + + {item.title} + + ); + })} +
+ ))} )} From f6b6bd2c4a94435ab3593d1f6de15f08b3632c3b Mon Sep 17 00:00:00 2001 From: Abhijai Srivastava Date: Mon, 29 Jun 2026 20:03:06 +0530 Subject: [PATCH 03/24] docs: add self-hosting environment variables reference page TH-6328 --- .../configuration/environment.mdx | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/pages/docs/self-hosting/configuration/environment.mdx diff --git a/src/pages/docs/self-hosting/configuration/environment.mdx b/src/pages/docs/self-hosting/configuration/environment.mdx new file mode 100644 index 00000000..8b499e3f --- /dev/null +++ b/src/pages/docs/self-hosting/configuration/environment.mdx @@ -0,0 +1,130 @@ +--- +title: "Environment Variables" +description: "Full .env reference for self-hosted Future AGI — required secrets, database credentials, runtime flags, LLM provider keys, email, and frontend build-time configuration." +--- + +## Introduction + +Every setting the stack reads at boot comes from a single `.env` file in the repo root. This page is the complete reference, grouped by what each variable does. The stack boots fine with the shipped defaults — the only thing you *must* change before sharing the instance is the `CHANGEME` secrets. + +```bash +cp .env.example .env +``` + + +Doing a local trial? Skip straight to [Install](/docs/self-hosting/install) — the defaults work as-is. Come back here when you're ready to set secrets, add LLM provider keys, or turn on email. + + +## Required Secrets + +Replace every `CHANGEME` in this group before anyone else can reach the instance. Generate each value with the command shown. + +| Variable | Generate with | Used by | +|---|---|---| +| `SECRET_KEY` | `openssl rand -hex 32` | Django sessions, CSRF, password reset | +| `PG_PASSWORD` | `openssl rand -base64 24` | PostgreSQL auth | +| `MINIO_ROOT_PASSWORD` | `openssl rand -base64 24` | MinIO object storage auth | +| `AGENTCC_INTERNAL_API_KEY` | `openssl rand -hex 32` | Backend ↔ gateway shared secret | + + +`PG_PASSWORD` is written to the Postgres volume on **first boot only**. If you change it after the volume exists, authentication fails — see the fix in [Troubleshooting](/docs/self-hosting/troubleshooting). Set it before your first `docker compose up`. + + +## Database Credentials + +| Variable | Default | Notes | +|---|---|---| +| `PG_USER` | `futureagi` | PostgreSQL username | +| `PG_PASSWORD` | `CHANGEME` | **Must change** | +| `PG_DB` | `futureagi` | PostgreSQL database name | +| `MINIO_ROOT_USER` | `futureagi` | MinIO username | +| `MINIO_ROOT_PASSWORD` | `CHANGEME` | **Must change** | +| `CH_USE_REPLICATED_ENGINES` | `false` | `true` only for multi-node ClickHouse | + +## Ports + +Every service port is configurable. The full table — defaults, what each binds to, and exposure scope — lives in [Requirements → Ports and Firewall](/docs/self-hosting/requirements#ports-and-firewall), so you can plan firewall rules in one place. + +## Backend Runtime + +| Variable | Default | Description | +|---|---|---| +| `ENV_TYPE` | `development` | `development` · `staging` · `prod`. Prod mode disables debug output and enables `check --deploy`. | +| `FAST_STARTUP` | `false` | Skip migrations on restart (dev only). Always `false` in production. | +| `GRANIAN_WORKERS` | `1` | ASGI worker processes. Set to your CPU count in production. | +| `GRANIAN_THREADS` | `2` | Threads per worker. | +| `ENABLE_GRPC` | `true` | Enable the gRPC endpoint. | +| `ENABLE_HTTP` | `true` | Enable the HTTP/REST endpoint. | + +## Temporal Worker + +| Variable | Default | Description | +|---|---|---| +| `TEMPORAL_NAMESPACE` | `default` | Temporal namespace. | +| `TEMPORAL_ALL_QUEUES` | `true` | Single worker polls all queues. Set `false` and use the dev overlay for per-queue workers. | +| `TEMPORAL_MAX_CONCURRENT_ACTIVITIES` | `50` | Max concurrent activity tasks. | +| `TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASKS` | `50` | Max concurrent workflow tasks. | + +Tuning guidance lives in [System Configuration → Temporal Workers](/docs/self-hosting/configuration/system#temporal-workers). + +## LLM Gateway + +| Variable | Default | Description | +|---|---|---| +| `AGENTCC_INTERNAL_API_KEY` | `CHANGEME` | **Must change.** The backend authenticates gateway calls with this shared secret. | + +Setting a key here is only half the job — the gateway also needs a `config.yaml` listing the providers it may route to. See [System Configuration → LLM Gateway](/docs/self-hosting/configuration/system#llm-gateway). + +## LLM Provider Keys + +Set a key for each provider you'll use and leave the rest blank. These are read by the gateway via `${VAR}` interpolation in `config.yaml`. + +| Variable | Provider | +|---|---| +| `OPENAI_API_KEY` | OpenAI | +| `ANTHROPIC_API_KEY` | Anthropic | +| `GOOGLE_API_KEY` | Google Gemini | +| `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_REGION` | AWS Bedrock + S3 | + +## Email (Mailgun) + +Email delivery powers self-service sign-up and password reset. Without it, you create users from the Django shell during [Install](/docs/self-hosting/install). Set these to turn on the email flow: + +| Variable | Description | +|---|---| +| `MAILGUN_API_KEY` | Mailgun private API key | +| `MAILGUN_SENDER_DOMAIN` | Verified Mailgun sending domain | +| `DEFAULT_FROM_EMAIL` | `From:` address for outbound email | +| `SERVER_EMAIL` | `From:` address for Django admin error email | + +## Frontend Build-Time + + +These are baked into the JavaScript bundle at Vite build time. Changing them requires a rebuild: `docker compose build frontend`. + + +| Variable | Default | Description | +|---|---|---| +| `VITE_HOST_API` | `http://localhost:8000` | Backend URL as seen by the browser. In production, use your public backend URL. | +| `VITE_ENVIRONMENT` | `development` | Frontend analytics and feature flags. | + +## Optional + +| Variable | Default | Description | +|---|---|---| +| `RECAPTCHA_ENABLED` | `false` | Enable reCAPTCHA on registration. | +| `RECAPTCHA_SECRET_KEY` | — | reCAPTCHA v2/v3 server-side key. | +| `VITE_GOOGLE_SITE_KEY` | — | reCAPTCHA client-side key (requires a frontend rebuild). | +| `FUTURE_AGI_CLOUD_API_KEY` | — | Enterprise-tier Cloud features only. Leave blank for the open-source build. | +| `FUTURE_AGI_CLOUD_API_URL` | `https://api.futureagi.com` | Do not change. | + +## Dive Deeper + + + + Point the LLM gateway at your providers and set up PeerDB mirrors. + + + Harden the instance before exposing it to users. + + From 6f37ddc92aa91ac18d857b2084196e293c0f55fa Mon Sep 17 00:00:00 2001 From: Yash Mohan Date: Mon, 29 Jun 2026 20:23:20 +0530 Subject: [PATCH 04/24] Self-hosting: rework Requirements page, add Requirements + Installation sidebar entries - Requirements-only pre-install checklist: hardware tiers, software (Docker 24.0+, Compose v2.20+, Git 2.0+) with per-OS install tabs, platform compatibility, and the network-ports reference. - Correct to current repo facts: AGENTCC_GATEWAY_PORT, 0.0.0.0 app-service binds, PeerDB ports only under COMPOSE_PROFILES=full. - Add Git as a prerequisite; fix the Windows WSL 2 memory guidance. - Sidebar: rename 'System requirements' -> 'Requirements' and add 'Installation'. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/lib/navigation.ts | 3 +- src/pages/docs/self-hosting/requirements.mdx | 71 ++++++++++---------- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts index 059c31d7..32731ba4 100644 --- a/src/lib/navigation.ts +++ b/src/lib/navigation.ts @@ -60,7 +60,8 @@ export const tabNavigation: NavTab[] = [ title: 'Self-Hosting', items: [ { title: 'Overview', href: '/docs/self-hosting' }, - { title: 'System requirements', href: '/docs/self-hosting/requirements' }, + { title: 'Requirements', href: '/docs/self-hosting/requirements' }, + { title: 'Installation', href: '/docs/self-hosting/install' }, { title: 'Environment variables', href: '/docs/self-hosting/environment' }, { title: 'Configuration', href: '/docs/self-hosting/configuration' }, { title: 'Docker Compose', href: '/docs/self-hosting/docker-compose' }, diff --git a/src/pages/docs/self-hosting/requirements.mdx b/src/pages/docs/self-hosting/requirements.mdx index 4e0ce3be..627cdf3e 100644 --- a/src/pages/docs/self-hosting/requirements.mdx +++ b/src/pages/docs/self-hosting/requirements.mdx @@ -1,24 +1,30 @@ --- -title: "Self-Hosting Requirements" -description: "Hardware sizing tiers, supported platforms, OS compatibility, and network port requirements before deploying Future AGI with Docker Compose." +title: "Self-hosting requirements" +description: "Hardware sizing tiers, supported platforms, OS compatibility, Docker versions, and the network ports each service uses. Everything you need to size and prepare a host before installing Future AGI." --- -## About +## Introduction -Hardware tiers, supported platforms, and the network ports each service uses. Read this first to size your environment before running [Docker Compose](/docs/self-hosting/docker-compose). +Check three things before you install: a host that meets the sizing for your usage, the required software (Docker and Git), and a supported platform. Get these right and the [Install](/docs/self-hosting/install) run works on the first try. + + +Short on time? For a local trial you need **4 CPU cores, 8 GB RAM, 20 GB disk**, Docker Engine 24+, and Docker Compose v2.20+. Everything below is the detail behind those numbers. + ## Hardware tiers +Pick the row that matches how you'll use the instance. The stack runs on the Evaluation tier, but ClickHouse and the Temporal worker are the resource drivers. Under-provisioning RAM is the most common cause of a failed first boot. + | Tier | Use case | CPU | RAM | Disk | |---|---|---|---|---| | **Evaluation** | Local trial, single user | 4 cores | 8 GB | 20 GB | -| **Team** | 1–20 users, regular eval runs | 8 cores | 16 GB | 50 GB | +| **Team** | 1-20 users, regular eval runs | 8 cores | 16 GB | 50 GB | | **Production** | 20+ users, high throughput | 16+ cores | 32+ GB | 200 GB+ SSD | -Resource drivers: ClickHouse and Temporal worker each hold ~1 GB RAM at steady state. First image build is ~6 GB disk. ClickHouse grows with trace volume; Postgres stays small. +ClickHouse and the Temporal worker each hold ~1 GB RAM at steady state. ClickHouse grows with trace volume over time; Postgres stays small. Pulling the images takes a few GB of disk on the first run. -Docker Desktop (Mac/Windows): Settings → Resources → set RAM ≥ 8 GB, disk ≥ 64 GB. The defaults (2–4 GB RAM) will OOM-kill ClickHouse or the backend. +On Docker Desktop (Mac/Windows), raise the limits in **Settings → Resources**: RAM ≥ 8 GB, disk ≥ 64 GB. The defaults (2-4 GB RAM) will OOM-kill ClickHouse or the backend before the stack finishes booting. ## Software @@ -27,70 +33,61 @@ Docker Desktop (Mac/Windows): Settings → Resources → set RAM ≥ 8 GB, disk |---|---|---| | Docker Engine | 24.0+ | `docker --version` | | Docker Compose | v2.20+ | `docker compose version` | +| Git | 2.0+ | `git --version` | ```bash -brew install docker docker-compose colima +brew install docker docker-compose colima git colima start --cpu 4 --memory 8 --disk 64 ``` -Or install [Docker Desktop for Mac](https://docs.docker.com/desktop/setup/install/mac-install/) and allocate ≥ 8 GB RAM in Settings → Resources. +Or install [Docker Desktop for Mac](https://docs.docker.com/desktop/setup/install/mac-install/) and allocate ≥ 8 GB RAM in **Settings → Resources**. ```bash -sudo apt-get install -y docker.io docker-compose-v2 +sudo apt-get install -y docker.io docker-compose-v2 git sudo systemctl enable --now docker sudo usermod -aG docker $USER # log out and back in ``` -Install [Docker Desktop for Windows](https://docs.docker.com/desktop/setup/install/windows-install/) with WSL 2 backend. Allocate ≥ 8 GB RAM in Settings → Resources. +Install [Docker Desktop for Windows](https://docs.docker.com/desktop/setup/install/windows-install/) with the WSL 2 backend. With WSL 2, memory is set in WSL, not Docker's UI: add `memory=8GB` under a `[wsl2]` section in `%UserProfile%\.wslconfig`, then run `wsl --shutdown` to apply. The **Settings → Resources** sliders apply only to the Hyper-V backend. ## Platform compatibility -The `code-executor` service requires `privileged: true`. Platforms that block it will crash the service; the rest of the stack still runs. +Future AGI runs on any host that allows **privileged containers**. The `code-executor` service needs `privileged: true` to sandbox the user code it runs for evaluations, so platforms that block privileged mode lose that one service: the rest of the stack still runs, but code-based eval features are unavailable. | Platform | Supported | Notes | |---|---|---| | Linux bare metal / EC2 / GCE / Azure VM | Yes | Full support | -| GKE / EKS with privileged enabled | Yes | Requires PodSecurityPolicy exception | +| GKE / EKS with privileged enabled | Yes | Requires a PodSecurityPolicy exception | | ECS Fargate | No | `privileged: true` not supported | | Google Cloud Run | No | Same | | Render / Railway / Fly.io | No | Managed platforms block privileged mode | -## Ports reference +Helm/Kubernetes and air-gapped install are on the roadmap. Docker Compose is the supported path today. + +## Network ports -All ports are configurable via `.env`. +Make sure these host ports are free before you install, or remap any that collide. Every published port reads from `.env` with a built-in default (for example `${FRONTEND_PORT:-3000}`), so you can change one without touching the Compose file. -| Service | Default | Exposed to | `.env` key | +| Service | Default | Bind | `.env` key | |---|---|---|---| | Frontend | `3000` | `0.0.0.0` | `FRONTEND_PORT` | | Backend API | `8000` | `0.0.0.0` | `BACKEND_PORT` | -| Gateway | `8090` | Internal only | `GATEWAY_PORT` | -| Model serving | `8080` | Internal only | `SERVING_PORT` | -| Code executor | `8060` | Internal only | `CODE_EXECUTOR_PORT` | -| Postgres | `5432` | `127.0.0.1` (dev: public) | `PG_PORT` | -| ClickHouse HTTP | `8123` | `127.0.0.1` (dev: public) | `CH_HTTP_PORT` | -| ClickHouse TCP | `9000` | `127.0.0.1` (dev: public) | `CH_PORT` | -| Redis | `6379` | `127.0.0.1` (dev: public) | `REDIS_PORT` | +| Gateway | `8090` | `0.0.0.0` | `AGENTCC_GATEWAY_PORT` | +| Model serving | `8080` | `0.0.0.0` | `SERVING_PORT` | +| Code executor | `8060` | `0.0.0.0` | `CODE_EXECUTOR_PORT` | +| Postgres | `5432` | `127.0.0.1` | `PG_PORT` | +| ClickHouse HTTP | `8123` | `127.0.0.1` | `CH_HTTP_PORT` | +| ClickHouse TCP | `9000` | `127.0.0.1` | `CH_PORT` | +| Redis | `6379` | `127.0.0.1` | `REDIS_PORT` | | MinIO API | `9005` | `127.0.0.1` | `MINIO_API_PORT` | | MinIO console | `9006` | `127.0.0.1` | `MINIO_CONSOLE_PORT` | -| Temporal | `7233` | `127.0.0.1` (dev: public) | `TEMPORAL_PORT` | -| Temporal UI | `8085` | Dev mode only | `TEMPORAL_UI_PORT` | +| Temporal | `7233` | `127.0.0.1` | `TEMPORAL_PORT` | | PeerDB server | `9900` | `127.0.0.1` | `PEERDB_PORT` | | PeerDB UI | `3001` | `0.0.0.0` | `PEERDB_UI_PORT` | -In production, only the frontend and backend ports should be internet-facing, and only behind a TLS-terminating reverse proxy. - -## Next Steps - - - - Clone, configure, and run the full stack. - - - Set secrets and tune runtime flags before first boot. - - +The data stores (Postgres, ClickHouse, Redis, MinIO, Temporal) bind to `127.0.0.1`; the application services bind to `0.0.0.0`. PeerDB server and UI only run when you enable the CDC stack with `COMPOSE_PROFILES=full`, so those two ports are only in use in that mode. From d3431e6f858ec0f762d3932fdc1c93e71bcc01a4 Mon Sep 17 00:00:00 2001 From: Yash Mohan Date: Mon, 29 Jun 2026 20:24:21 +0530 Subject: [PATCH 05/24] Self-hosting: add Installation page + sidebar entries - New Installation page for the current ./bin/install flow: Steps (clone + install, create first user via manage.py create_user, open the app), installer flags, Apple Silicon/arm64 note, manual install, verify-the-stack, everyday operations, and the dev/frontend run modes. - 'Deep dive' card to Environment variables (System configuration card omitted since that page is not in the base branch). - Replaces the old build-from-source v1.8.19_base draft with the published-image flow; every command verified against the live future-agi/future-agi repo. - Sidebar: rename 'System requirements' -> 'Requirements' and add 'Installation'. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/lib/navigation.ts | 3 +- src/pages/docs/self-hosting/install.mdx | 128 ++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 src/pages/docs/self-hosting/install.mdx diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts index 059c31d7..32731ba4 100644 --- a/src/lib/navigation.ts +++ b/src/lib/navigation.ts @@ -60,7 +60,8 @@ export const tabNavigation: NavTab[] = [ title: 'Self-Hosting', items: [ { title: 'Overview', href: '/docs/self-hosting' }, - { title: 'System requirements', href: '/docs/self-hosting/requirements' }, + { title: 'Requirements', href: '/docs/self-hosting/requirements' }, + { title: 'Installation', href: '/docs/self-hosting/install' }, { title: 'Environment variables', href: '/docs/self-hosting/environment' }, { title: 'Configuration', href: '/docs/self-hosting/configuration' }, { title: 'Docker Compose', href: '/docs/self-hosting/docker-compose' }, diff --git a/src/pages/docs/self-hosting/install.mdx b/src/pages/docs/self-hosting/install.mdx new file mode 100644 index 00000000..41f626f3 --- /dev/null +++ b/src/pages/docs/self-hosting/install.mdx @@ -0,0 +1,128 @@ +--- +title: "Install with Docker Compose" +description: "Bring up a self-hosted Future AGI instance with Docker Compose: clone the repo, run the installer, verify the stack, and create your first admin user." +--- + +## Introduction + +Docker Compose is the supported way to run a self-hosted Future AGI instance. Once you have the repo, `./bin/install` bootstraps your `.env`, brings up the stack from published images, waits for the backend health check, and prompts you to create the first user. First boot pulls images from Docker Hub and takes about a minute, with no source builds. Confirm your host meets the [requirements](/docs/self-hosting/requirements) first. + + +Short on time? Run `git clone https://github.com/future-agi/future-agi.git && cd future-agi && ./bin/install`, then open [http://localhost:3000](http://localhost:3000). Everything below is the detail behind that one command. + + +## Install + + + +```bash +git clone https://github.com/future-agi/future-agi.git +cd future-agi +./bin/install # Windows: bin\install.ps1 +``` + +The installer copies `.env.example` to `.env` if you do not have one, runs `docker compose up -d`, polls `http://localhost:8000/health/` until the backend is ready, then prompts you to create your first user. The stack boots fine against an empty `.env`, so you can take the defaults for a local trial. + +By default the installer brings up the standard stack (around 12 containers). Add `--full` to include the PeerDB CDC stack (around 22 containers) that populates the analytics views. + + + +The installer prompts you at the end. If you passed `--skip-user-creation`, create the account from the CLI instead: + +```bash +docker compose exec backend python manage.py create_user +``` + +You will be asked for an email, full name, and password. To script it, pass them inline: + +```bash +docker compose exec backend python manage.py create_user \ + --email you@example.com \ + --name "Your Name" \ + --password yourpassword +``` + + + +Log in at [http://localhost:3000](http://localhost:3000) with the user you just created. The backend API is at [http://localhost:8000](http://localhost:8000). + + + +### Installer flags + +| Flag | What it does | +|---|---| +| `--full` | Add the PeerDB CDC stack (around 22 containers) so the analytics views populate. | +| `--skip-user-creation` | Skip the first-user prompt. Create the account later with `create_user`. | +| `--no-up` | Bootstrap `.env` only. Do not start the stack. | +| `--wipe-volumes` | Remove stale project volumes before starting. This destroys existing data. | +| `--new-instance` | Start a fresh instance when existing volumes are detected. | + + +**Apple Silicon and arm64 hosts.** Prebuilt images are `linux/amd64`. On M-series Macs they run under Rosetta 2 (auto-enabled on Docker Desktop 4.16+), which is fine for evaluation with a 20 to 50 percent performance cost. For native arm64, build locally with `docker compose build` instead of pulling. On Linux arm64 such as Graviton, install `qemu-user-static`. + + +## Install without the script + +The installer is a convenience wrapper, not a requirement. To run the same steps by hand: + +```bash +cp .env.example .env # optional; an empty .env works for local +docker compose up -d +``` + +Then create the first user with the same `create_user` command shown above. + +## Verify the stack + +Check that every service is healthy before you log in. Under-provisioned RAM is the most common reason the backend never finishes booting, so confirm the [requirements](/docs/self-hosting/requirements) if it stalls. + +```bash +docker compose ps # every service should read "running" or "healthy" +docker compose logs -f backend # wait for "Application startup complete" +curl http://localhost:8000/health/ +``` + +When the backend logs `Application startup complete` and the health endpoint returns OK, the instance is ready. + +## Everyday operations + +A short reference for the commands you will use most: + +```bash +# Tail logs +docker compose logs -f backend worker + +# Shell into a container +docker compose exec backend bash +docker compose exec postgres psql -U futureagi -d futureagi + +# Stop the stack (data persists in named volumes) +./bin/uninstall # or: docker compose down + +# Wipe all data and start clean +./bin/uninstall --wipe-data # or: docker compose down -v + +# Remove everything: containers, volumes, .env, and built images +./bin/uninstall --purge +``` + +## Other ways to run it + +| Mode | Command | Use it for | +|---|---|---| +| Standard (default) | `docker compose up -d` | Local evaluation, team installs, and VM self-hosting. | +| Development | `docker compose -f docker-compose.yml -f docker-compose.dev.yml up` | Contributing to Future AGI: hot reload, per-queue workers, host-accessible database ports, and the Temporal UI. | +| Frontend only | `docker compose -f docker-compose.frontend.yml up -d` | Pointing a local UI at a backend that runs elsewhere. | + + +For a frontend-only deploy, set `VITE_HOST_API` to the backend URL the browser can reach. It is applied when the container starts, so changing it needs only a restart of the frontend container, not a rebuild. + + +## Deep dive + + + + Set provider keys, secrets, and runtime flags in `.env`. + + From 2402c83aef51f399443ed4935a478e2ca33cc099 Mon Sep 17 00:00:00 2001 From: Abhijai Srivastava Date: Wed, 1 Jul 2026 17:23:05 +0530 Subject: [PATCH 06/24] docs: align frontmatter with review standards - title: sentence case to match sidebar label - description: remove em-dash, shorten to single purpose line - convert short-on-time Note to TLDR - remove em-dash from intro paragraph TH-6328 --- .../docs/self-hosting/configuration/environment.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/docs/self-hosting/configuration/environment.mdx b/src/pages/docs/self-hosting/configuration/environment.mdx index 8b499e3f..e4a79eb1 100644 --- a/src/pages/docs/self-hosting/configuration/environment.mdx +++ b/src/pages/docs/self-hosting/configuration/environment.mdx @@ -1,19 +1,19 @@ --- -title: "Environment Variables" -description: "Full .env reference for self-hosted Future AGI — required secrets, database credentials, runtime flags, LLM provider keys, email, and frontend build-time configuration." +title: "Environment variables" +description: "Complete .env reference for a self-hosted Future AGI instance." --- ## Introduction -Every setting the stack reads at boot comes from a single `.env` file in the repo root. This page is the complete reference, grouped by what each variable does. The stack boots fine with the shipped defaults — the only thing you *must* change before sharing the instance is the `CHANGEME` secrets. +Every setting the stack reads at boot comes from a single `.env` file in the repo root. This page is the complete reference, grouped by what each variable does. The stack boots fine with the shipped defaults. The only thing you *must* change before sharing the instance is the `CHANGEME` secrets. ```bash cp .env.example .env ``` - -Doing a local trial? Skip straight to [Install](/docs/self-hosting/install) — the defaults work as-is. Come back here when you're ready to set secrets, add LLM provider keys, or turn on email. - + +Doing a local trial? Skip to [Install](/docs/self-hosting/install). The defaults work as-is. Come back here when you're ready to set secrets, add LLM provider keys, or turn on email. + ## Required Secrets From 76f4b8eaefc8b3a83e528b1fb704e925f704de1b Mon Sep 17 00:00:00 2001 From: Yash Mohan Date: Thu, 2 Jul 2026 13:30:14 +0530 Subject: [PATCH 07/24] docs(self-hosting): address Khushal review on Requirements (#696) - Title -> 'Requirements' (sync with sidebar); shorten description. - 'Introduction' -> 'In this page'; intro three-checks as bullets. - Note -> TLDR for the short-on-time summary. - Uniform OS tabs (consistent lead line); remove stranded macOS Docker Desktop line. - Update Install link + nav href for the install -> installation rename. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/lib/navigation.ts | 2 +- src/pages/docs/self-hosting/requirements.mdx | 25 +++++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts index 32731ba4..ca09232f 100644 --- a/src/lib/navigation.ts +++ b/src/lib/navigation.ts @@ -61,7 +61,7 @@ export const tabNavigation: NavTab[] = [ items: [ { title: 'Overview', href: '/docs/self-hosting' }, { title: 'Requirements', href: '/docs/self-hosting/requirements' }, - { title: 'Installation', href: '/docs/self-hosting/install' }, + { title: 'Installation', href: '/docs/self-hosting/installation' }, { title: 'Environment variables', href: '/docs/self-hosting/environment' }, { title: 'Configuration', href: '/docs/self-hosting/configuration' }, { title: 'Docker Compose', href: '/docs/self-hosting/docker-compose' }, diff --git a/src/pages/docs/self-hosting/requirements.mdx b/src/pages/docs/self-hosting/requirements.mdx index 627cdf3e..f23aa952 100644 --- a/src/pages/docs/self-hosting/requirements.mdx +++ b/src/pages/docs/self-hosting/requirements.mdx @@ -1,15 +1,21 @@ --- -title: "Self-hosting requirements" -description: "Hardware sizing tiers, supported platforms, OS compatibility, Docker versions, and the network ports each service uses. Everything you need to size and prepare a host before installing Future AGI." +title: "Requirements" +description: "System requirements and support for self-hosting Future AGI." --- -## Introduction +## In this page -Check three things before you install: a host that meets the sizing for your usage, the required software (Docker and Git), and a supported platform. Get these right and the [Install](/docs/self-hosting/install) run works on the first try. +Check three things before you install: - -Short on time? For a local trial you need **4 CPU cores, 8 GB RAM, 20 GB disk**, Docker Engine 24+, and Docker Compose v2.20+. Everything below is the detail behind those numbers. - +- A host that meets the sizing for your usage +- The required software: Docker and Git +- A supported platform + +Get these right and the [Installation](/docs/self-hosting/installation) run works on the first try. + + +For a local trial: **4 CPU cores, 8 GB RAM, 20 GB disk**, Docker Engine 24+, Docker Compose v2.20+, and Git. + ## Hardware tiers @@ -37,13 +43,14 @@ On Docker Desktop (Mac/Windows), raise the limits in **Settings → Resources**: +Install the tools with Homebrew, then start Colima: ```bash brew install docker docker-compose colima git colima start --cpu 4 --memory 8 --disk 64 ``` -Or install [Docker Desktop for Mac](https://docs.docker.com/desktop/setup/install/mac-install/) and allocate ≥ 8 GB RAM in **Settings → Resources**. +Install the tools with apt, then enable the Docker daemon: ```bash sudo apt-get install -y docker.io docker-compose-v2 git sudo systemctl enable --now docker @@ -51,7 +58,7 @@ sudo usermod -aG docker $USER # log out and back in ``` -Install [Docker Desktop for Windows](https://docs.docker.com/desktop/setup/install/windows-install/) with the WSL 2 backend. With WSL 2, memory is set in WSL, not Docker's UI: add `memory=8GB` under a `[wsl2]` section in `%UserProfile%\.wslconfig`, then run `wsl --shutdown` to apply. The **Settings → Resources** sliders apply only to the Hyper-V backend. +Install [Docker Desktop for Windows](https://docs.docker.com/desktop/setup/install/windows-install/) with the WSL 2 backend, then set the memory limit in WSL, not Docker's UI: add `memory=8GB` under a `[wsl2]` section in `%UserProfile%\.wslconfig` and run `wsl --shutdown` to apply. The **Settings → Resources** sliders apply only to the Hyper-V backend. From c19c52d38c438c1563df0c9fbe957f6e8ec04b6d Mon Sep 17 00:00:00 2001 From: Yash Mohan Date: Thu, 2 Jul 2026 13:33:14 +0530 Subject: [PATCH 08/24] docs(self-hosting): address Khushal review on Installation (#697) - Rename install.mdx -> installation.mdx (file = kebab of sidebar title); nav href updated. - Title -> 'Installation'; shorten description. - 'Introduction' -> 'In this page'; bullet the installer-does-this enumeration (de-duped Step 1). - Note -> TLDR. Footer 'Deep dive' -> 'Dive deeper'. - Drop trailing periods in the flags + modes tables and the card body. - Point the env card at the canonical nav path /docs/self-hosting/environment. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/lib/navigation.ts | 2 +- .../{install.mdx => installation.mdx} | 45 +++++++++++-------- 2 files changed, 27 insertions(+), 20 deletions(-) rename src/pages/docs/self-hosting/{install.mdx => installation.mdx} (70%) diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts index 32731ba4..ca09232f 100644 --- a/src/lib/navigation.ts +++ b/src/lib/navigation.ts @@ -61,7 +61,7 @@ export const tabNavigation: NavTab[] = [ items: [ { title: 'Overview', href: '/docs/self-hosting' }, { title: 'Requirements', href: '/docs/self-hosting/requirements' }, - { title: 'Installation', href: '/docs/self-hosting/install' }, + { title: 'Installation', href: '/docs/self-hosting/installation' }, { title: 'Environment variables', href: '/docs/self-hosting/environment' }, { title: 'Configuration', href: '/docs/self-hosting/configuration' }, { title: 'Docker Compose', href: '/docs/self-hosting/docker-compose' }, diff --git a/src/pages/docs/self-hosting/install.mdx b/src/pages/docs/self-hosting/installation.mdx similarity index 70% rename from src/pages/docs/self-hosting/install.mdx rename to src/pages/docs/self-hosting/installation.mdx index 41f626f3..54d17e8f 100644 --- a/src/pages/docs/self-hosting/install.mdx +++ b/src/pages/docs/self-hosting/installation.mdx @@ -1,15 +1,22 @@ --- -title: "Install with Docker Compose" -description: "Bring up a self-hosted Future AGI instance with Docker Compose: clone the repo, run the installer, verify the stack, and create your first admin user." +title: "Installation" +description: "Install a self-hosted Future AGI instance with Docker Compose." --- -## Introduction +## In this page -Docker Compose is the supported way to run a self-hosted Future AGI instance. Once you have the repo, `./bin/install` bootstraps your `.env`, brings up the stack from published images, waits for the backend health check, and prompts you to create the first user. First boot pulls images from Docker Hub and takes about a minute, with no source builds. Confirm your host meets the [requirements](/docs/self-hosting/requirements) first. +Docker Compose is the supported way to run a self-hosted Future AGI instance. Confirm your host meets the [requirements](/docs/self-hosting/requirements) first, then `./bin/install` does the rest: - -Short on time? Run `git clone https://github.com/future-agi/future-agi.git && cd future-agi && ./bin/install`, then open [http://localhost:3000](http://localhost:3000). Everything below is the detail behind that one command. - +- Bootstraps your `.env` +- Brings up the stack from published images +- Waits for the backend health check +- Prompts you to create the first user + +First boot pulls images from Docker Hub and takes about a minute, with no source builds. + + +Run `git clone https://github.com/future-agi/future-agi.git && cd future-agi && ./bin/install`, then open [http://localhost:3000](http://localhost:3000). + ## Install @@ -21,7 +28,7 @@ cd future-agi ./bin/install # Windows: bin\install.ps1 ``` -The installer copies `.env.example` to `.env` if you do not have one, runs `docker compose up -d`, polls `http://localhost:8000/health/` until the backend is ready, then prompts you to create your first user. The stack boots fine against an empty `.env`, so you can take the defaults for a local trial. +The stack boots fine against an empty `.env`, so you can take the defaults for a local trial. By default the installer brings up the standard stack (around 12 containers). Add `--full` to include the PeerDB CDC stack (around 22 containers) that populates the analytics views. @@ -52,11 +59,11 @@ Log in at [http://localhost:3000](http://localhost:3000) with the user you just | Flag | What it does | |---|---| -| `--full` | Add the PeerDB CDC stack (around 22 containers) so the analytics views populate. | -| `--skip-user-creation` | Skip the first-user prompt. Create the account later with `create_user`. | -| `--no-up` | Bootstrap `.env` only. Do not start the stack. | -| `--wipe-volumes` | Remove stale project volumes before starting. This destroys existing data. | -| `--new-instance` | Start a fresh instance when existing volumes are detected. | +| `--full` | Add the PeerDB CDC stack (around 22 containers) so the analytics views populate | +| `--skip-user-creation` | Skip the first-user prompt; create the account later with `create_user` | +| `--no-up` | Bootstrap `.env` only, without starting the stack | +| `--wipe-volumes` | Remove stale project volumes before starting (destroys existing data) | +| `--new-instance` | Start a fresh instance when existing volumes are detected | **Apple Silicon and arm64 hosts.** Prebuilt images are `linux/amd64`. On M-series Macs they run under Rosetta 2 (auto-enabled on Docker Desktop 4.16+), which is fine for evaluation with a 20 to 50 percent performance cost. For native arm64, build locally with `docker compose build` instead of pulling. On Linux arm64 such as Graviton, install `qemu-user-static`. @@ -111,18 +118,18 @@ docker compose exec postgres psql -U futureagi -d futureagi | Mode | Command | Use it for | |---|---|---| -| Standard (default) | `docker compose up -d` | Local evaluation, team installs, and VM self-hosting. | -| Development | `docker compose -f docker-compose.yml -f docker-compose.dev.yml up` | Contributing to Future AGI: hot reload, per-queue workers, host-accessible database ports, and the Temporal UI. | -| Frontend only | `docker compose -f docker-compose.frontend.yml up -d` | Pointing a local UI at a backend that runs elsewhere. | +| Standard (default) | `docker compose up -d` | Local evaluation, team installs, and VM self-hosting | +| Development | `docker compose -f docker-compose.yml -f docker-compose.dev.yml up` | Contributing to Future AGI: hot reload, per-queue workers, host-accessible database ports, and the Temporal UI | +| Frontend only | `docker compose -f docker-compose.frontend.yml up -d` | Pointing a local UI at a backend that runs elsewhere | For a frontend-only deploy, set `VITE_HOST_API` to the backend URL the browser can reach. It is applied when the container starts, so changing it needs only a restart of the frontend container, not a rebuild. -## Deep dive +## Dive deeper - - Set provider keys, secrets, and runtime flags in `.env`. + + Set provider keys, secrets, and runtime flags in `.env` From e26cb58f5e174449a66bc5f6296ddbf30ec8afb6 Mon Sep 17 00:00:00 2001 From: Abhijai Srivastava Date: Thu, 2 Jul 2026 16:26:48 +0530 Subject: [PATCH 09/24] docs: add self-hosting environment variables page Complete .env reference under Configuration, self-reviewed against the docs review guide (review-docs-like-khushal). TH-6328 --- .../configuration/environment.mdx | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/pages/docs/self-hosting/configuration/environment.mdx diff --git a/src/pages/docs/self-hosting/configuration/environment.mdx b/src/pages/docs/self-hosting/configuration/environment.mdx new file mode 100644 index 00000000..c56cc2c4 --- /dev/null +++ b/src/pages/docs/self-hosting/configuration/environment.mdx @@ -0,0 +1,130 @@ +--- +title: "Environment variables" +description: "Complete .env reference for a self-hosted Future AGI instance" +--- + +## In this page + +Every setting the stack reads at boot comes from a single `.env` file in the repo root. This page is the complete reference, grouped by what each variable does. The stack boots fine with the shipped defaults. The only thing you *must* change before sharing the instance is the `CHANGEME` secrets. + +```bash +cp .env.example .env +``` + + +Doing a local trial? Skip to [Docker Compose](/docs/self-hosting/docker-compose). The defaults work as-is. Come back here when you're ready to set secrets, add LLM provider keys, or turn on email. + + +## Required Secrets + +Replace every `CHANGEME` in this group before anyone else can reach the instance. Generate each value with the command shown. + +| Variable | Generate with | Used by | +|---|---|---| +| `SECRET_KEY` | `openssl rand -hex 32` | Django sessions, CSRF, password reset | +| `PG_PASSWORD` | `openssl rand -base64 24` | PostgreSQL auth | +| `MINIO_ROOT_PASSWORD` | `openssl rand -base64 24` | MinIO object storage auth | +| `AGENTCC_INTERNAL_API_KEY` | `openssl rand -hex 32` | Backend and gateway shared secret | + + +`PG_PASSWORD` is written to the Postgres volume on **first boot only**. If you change it after the volume exists, authentication fails. See the fix in [Troubleshooting](/docs/self-hosting/troubleshooting). Set it before your first `docker compose up`. + + +## Database Credentials + +| Variable | Default | Notes | +|---|---|---| +| `PG_USER` | `futureagi` | PostgreSQL username | +| `PG_PASSWORD` | `CHANGEME` | **Must change** | +| `PG_DB` | `futureagi` | PostgreSQL database name | +| `MINIO_ROOT_USER` | `futureagi` | MinIO username | +| `MINIO_ROOT_PASSWORD` | `CHANGEME` | **Must change** | +| `CH_USE_REPLICATED_ENGINES` | `false` | `true` only for multi-node ClickHouse | + +## Ports + +Every service port is configurable. The full table (defaults, what each binds to, and exposure scope) lives in [Requirements](/docs/self-hosting/requirements#ports-reference), so you can plan firewall rules in one place. + +## Backend Runtime + +| Variable | Default | Description | +|---|---|---| +| `ENV_TYPE` | `development` | One of `development`, `staging`, or `prod`. Prod mode disables debug output and enables `check --deploy` | +| `FAST_STARTUP` | `false` | Skip migrations on restart (dev only). Always `false` in production | +| `GRANIAN_WORKERS` | `1` | ASGI worker processes. Set to your CPU count in production | +| `GRANIAN_THREADS` | `2` | Threads per worker | +| `ENABLE_GRPC` | `true` | Enable the gRPC endpoint | +| `ENABLE_HTTP` | `true` | Enable the HTTP/REST endpoint | + +## Temporal Worker + +| Variable | Default | Description | +|---|---|---| +| `TEMPORAL_NAMESPACE` | `default` | Temporal namespace | +| `TEMPORAL_ALL_QUEUES` | `true` | Single worker polls all queues. Set `false` and use the dev overlay for per-queue workers | +| `TEMPORAL_MAX_CONCURRENT_ACTIVITIES` | `50` | Max concurrent activity tasks | +| `TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASKS` | `50` | Max concurrent workflow tasks | + +Tuning guidance lives in [System Configuration](/docs/self-hosting/configuration). + +## LLM Gateway + +| Variable | Default | Description | +|---|---|---| +| `AGENTCC_INTERNAL_API_KEY` | `CHANGEME` | **Must change.** The backend authenticates gateway calls with this shared secret | + +Setting a key here is only half the job. The gateway also needs a `config.yaml` listing the providers it may route to. See System Configuration for the full setup. + +## LLM Provider Keys + +Set a key for each provider you'll use and leave the rest blank. These are read by the gateway via `${VAR}` interpolation in `config.yaml`. + +| Variable | Provider | +|---|---| +| `OPENAI_API_KEY` | OpenAI | +| `ANTHROPIC_API_KEY` | Anthropic | +| `GOOGLE_API_KEY` | Google Gemini | +| `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_REGION` | AWS Bedrock + S3 | + +## Email (Mailgun) + +Email delivery powers self-service sign-up and password reset. Without it, you create users manually from the Django shell after bringing up the stack. Set these to turn on the email flow: + +| Variable | Description | +|---|---| +| `MAILGUN_API_KEY` | Mailgun private API key | +| `MAILGUN_SENDER_DOMAIN` | Verified Mailgun sending domain | +| `DEFAULT_FROM_EMAIL` | `From:` address for outbound email | +| `SERVER_EMAIL` | `From:` address for Django admin error email | + +## Frontend Build-Time + + +These are baked into the JavaScript bundle at Vite build time. Changing them requires a rebuild: `docker compose build frontend`. + + +| Variable | Default | Description | +|---|---|---| +| `VITE_HOST_API` | `http://localhost:8000` | Backend URL as seen by the browser. In production, use your public backend URL | +| `VITE_ENVIRONMENT` | `development` | Frontend analytics and feature flags | + +## Optional + +| Variable | Default | Description | +|---|---|---| +| `RECAPTCHA_ENABLED` | `false` | Enable reCAPTCHA on registration | +| `RECAPTCHA_SECRET_KEY` | `(none)` | reCAPTCHA v2/v3 server-side key | +| `VITE_GOOGLE_SITE_KEY` | `(none)` | reCAPTCHA client-side key (requires a frontend rebuild) | +| `FUTURE_AGI_CLOUD_API_KEY` | `(none)` | Enterprise-tier Cloud features only. Leave blank for the open-source build | +| `FUTURE_AGI_CLOUD_API_URL` | `https://api.futureagi.com` | Do not change | + +## Dive deeper + + + + Point the LLM gateway at your providers and set up PeerDB mirrors + + + Harden the instance before exposing it to users + + From 700bc9714dd1f3e1e66241b5bb3fdb5d804749bf Mon Sep 17 00:00:00 2001 From: khushalsonawat Date: Mon, 6 Jul 2026 11:34:40 +0530 Subject: [PATCH 10/24] docs(self-hosting): rename Installation to Install; fix first-boot and readiness claims (#697 review) --- src/lib/navigation.ts | 2 +- .../{installation.mdx => install.mdx} | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) rename src/pages/docs/self-hosting/{installation.mdx => install.mdx} (87%) diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts index ca09232f..bf8de54f 100644 --- a/src/lib/navigation.ts +++ b/src/lib/navigation.ts @@ -61,7 +61,7 @@ export const tabNavigation: NavTab[] = [ items: [ { title: 'Overview', href: '/docs/self-hosting' }, { title: 'Requirements', href: '/docs/self-hosting/requirements' }, - { title: 'Installation', href: '/docs/self-hosting/installation' }, + { title: 'Install', href: '/docs/self-hosting/install' }, { title: 'Environment variables', href: '/docs/self-hosting/environment' }, { title: 'Configuration', href: '/docs/self-hosting/configuration' }, { title: 'Docker Compose', href: '/docs/self-hosting/docker-compose' }, diff --git a/src/pages/docs/self-hosting/installation.mdx b/src/pages/docs/self-hosting/install.mdx similarity index 87% rename from src/pages/docs/self-hosting/installation.mdx rename to src/pages/docs/self-hosting/install.mdx index 54d17e8f..7220f1a7 100644 --- a/src/pages/docs/self-hosting/installation.mdx +++ b/src/pages/docs/self-hosting/install.mdx @@ -1,18 +1,20 @@ --- -title: "Installation" +title: "Install" description: "Install a self-hosted Future AGI instance with Docker Compose." --- +Docker Compose is the supported way to run a self-hosted Future AGI instance. + ## In this page -Docker Compose is the supported way to run a self-hosted Future AGI instance. Confirm your host meets the [requirements](/docs/self-hosting/requirements) first, then `./bin/install` does the rest: +Confirm your host meets the [requirements](/docs/self-hosting/requirements) first, then `./bin/install` does the rest: - Bootstraps your `.env` -- Brings up the stack from published images +- Brings up the stack - Waits for the backend health check - Prompts you to create the first user -First boot pulls images from Docker Hub and takes about a minute, with no source builds. +First boot pulls the app images from Docker Hub and builds the small fi-collector image from source, so give it a few minutes the first time. Run `git clone https://github.com/future-agi/future-agi.git && cd future-agi && ./bin/install`, then open [http://localhost:3000](http://localhost:3000). @@ -86,11 +88,11 @@ Check that every service is healthy before you log in. Under-provisioned RAM is ```bash docker compose ps # every service should read "running" or "healthy" -docker compose logs -f backend # wait for "Application startup complete" +docker compose logs -f backend # watch for errors while it boots curl http://localhost:8000/health/ ``` -When the backend logs `Application startup complete` and the health endpoint returns OK, the instance is ready. +The instance is ready when `/health/` returns OK. That's the same check `./bin/install` polls while it waits for the backend. ## Everyday operations @@ -128,8 +130,11 @@ For a frontend-only deploy, set `VITE_HOST_API` to the backend URL the browser c ## Dive deeper - + Set provider keys, secrets, and runtime flags in `.env` + + Tune the gateway, PeerDB, and Temporal workers + From 9a218e768db8feef4002d58d10663afcd045b549 Mon Sep 17 00:00:00 2001 From: khushalsonawat Date: Mon, 6 Jul 2026 11:52:48 +0530 Subject: [PATCH 11/24] docs(self-hosting): rename Install back to Installation --- src/lib/navigation.ts | 2 +- src/pages/docs/self-hosting/configuration/environment.mdx | 4 ++-- src/pages/docs/self-hosting/{install.mdx => installation.mdx} | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/pages/docs/self-hosting/{install.mdx => installation.mdx} (99%) diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts index bf8de54f..ca09232f 100644 --- a/src/lib/navigation.ts +++ b/src/lib/navigation.ts @@ -61,7 +61,7 @@ export const tabNavigation: NavTab[] = [ items: [ { title: 'Overview', href: '/docs/self-hosting' }, { title: 'Requirements', href: '/docs/self-hosting/requirements' }, - { title: 'Install', href: '/docs/self-hosting/install' }, + { title: 'Installation', href: '/docs/self-hosting/installation' }, { title: 'Environment variables', href: '/docs/self-hosting/environment' }, { title: 'Configuration', href: '/docs/self-hosting/configuration' }, { title: 'Docker Compose', href: '/docs/self-hosting/docker-compose' }, diff --git a/src/pages/docs/self-hosting/configuration/environment.mdx b/src/pages/docs/self-hosting/configuration/environment.mdx index e4a79eb1..6e38d95d 100644 --- a/src/pages/docs/self-hosting/configuration/environment.mdx +++ b/src/pages/docs/self-hosting/configuration/environment.mdx @@ -12,7 +12,7 @@ cp .env.example .env ``` -Doing a local trial? Skip to [Install](/docs/self-hosting/install). The defaults work as-is. Come back here when you're ready to set secrets, add LLM provider keys, or turn on email. +Doing a local trial? Skip to [Installation](/docs/self-hosting/installation). The defaults work as-is. Come back here when you're ready to set secrets, add LLM provider keys, or turn on email. ## Required Secrets @@ -88,7 +88,7 @@ Set a key for each provider you'll use and leave the rest blank. These are read ## Email (Mailgun) -Email delivery powers self-service sign-up and password reset. Without it, you create users from the Django shell during [Install](/docs/self-hosting/install). Set these to turn on the email flow: +Email delivery powers self-service sign-up and password reset. Without it, you create users from the Django shell during [Installation](/docs/self-hosting/installation). Set these to turn on the email flow: | Variable | Description | |---|---| diff --git a/src/pages/docs/self-hosting/install.mdx b/src/pages/docs/self-hosting/installation.mdx similarity index 99% rename from src/pages/docs/self-hosting/install.mdx rename to src/pages/docs/self-hosting/installation.mdx index 7220f1a7..1b8cffd4 100644 --- a/src/pages/docs/self-hosting/install.mdx +++ b/src/pages/docs/self-hosting/installation.mdx @@ -1,5 +1,5 @@ --- -title: "Install" +title: "Installation" description: "Install a self-hosted Future AGI instance with Docker Compose." --- From 354b76ab772fcdccfb9567b79781d5524203cf8a Mon Sep 17 00:00:00 2001 From: Abhijai Srivastava Date: Thu, 2 Jul 2026 21:08:00 +0530 Subject: [PATCH 12/24] docs: restructure self-hosting sidebar; add Production subsection and Support Sidebar reshaped to the agreed tree: Configuration and Production as nested groups. Production split from the flat page into Checklist, Security & TLS, Backups & restore, Monitoring, and Upgrades & rollback. New Support page. Production overview slimmed to route into the subsection. --- src/lib/navigation.ts | 25 ++- src/pages/docs/self-hosting/production.mdx | 145 +++--------------- .../production/backups-restore.mdx | 68 ++++++++ .../self-hosting/production/checklist.mdx | 57 +++++++ .../self-hosting/production/monitoring.mdx | 46 ++++++ .../self-hosting/production/security-tls.mdx | 59 +++++++ .../production/upgrades-rollback.mdx | 59 +++++++ src/pages/docs/self-hosting/support.mdx | 43 ++++++ 8 files changed, 369 insertions(+), 133 deletions(-) create mode 100644 src/pages/docs/self-hosting/production/backups-restore.mdx create mode 100644 src/pages/docs/self-hosting/production/checklist.mdx create mode 100644 src/pages/docs/self-hosting/production/monitoring.mdx create mode 100644 src/pages/docs/self-hosting/production/security-tls.mdx create mode 100644 src/pages/docs/self-hosting/production/upgrades-rollback.mdx create mode 100644 src/pages/docs/self-hosting/support.mdx diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts index ca09232f..3ad68081 100644 --- a/src/lib/navigation.ts +++ b/src/lib/navigation.ts @@ -62,12 +62,25 @@ export const tabNavigation: NavTab[] = [ { title: 'Overview', href: '/docs/self-hosting' }, { title: 'Requirements', href: '/docs/self-hosting/requirements' }, { title: 'Installation', href: '/docs/self-hosting/installation' }, - { title: 'Environment variables', href: '/docs/self-hosting/environment' }, - { title: 'Configuration', href: '/docs/self-hosting/configuration' }, - { title: 'Docker Compose', href: '/docs/self-hosting/docker-compose' }, - { title: 'Production', href: '/docs/self-hosting/production' }, - { title: 'User management', href: '/docs/self-hosting/user-management' }, - { title: 'Troubleshooting and FAQs', href: '/docs/self-hosting/troubleshooting' }, + { + title: 'Configuration', + items: [ + { title: 'Environment variables', href: '/docs/self-hosting/environment' }, + { title: 'System configuration', href: '/docs/self-hosting/configuration' }, + ] + }, + { + title: 'Production', + items: [ + { title: 'Checklist', href: '/docs/self-hosting/production/checklist' }, + { title: 'Security & TLS', href: '/docs/self-hosting/production/security-tls' }, + { title: 'Backups & restore', href: '/docs/self-hosting/production/backups-restore' }, + { title: 'Monitoring', href: '/docs/self-hosting/production/monitoring' }, + { title: 'Upgrades & rollback', href: '/docs/self-hosting/production/upgrades-rollback' }, + ] + }, + { title: 'Troubleshooting & FAQs', href: '/docs/self-hosting/troubleshooting' }, + { title: 'Support', href: '/docs/self-hosting/support' }, ] }, ] diff --git a/src/pages/docs/self-hosting/production.mdx b/src/pages/docs/self-hosting/production.mdx index c5fbb682..5b0b2c5b 100644 --- a/src/pages/docs/self-hosting/production.mdx +++ b/src/pages/docs/self-hosting/production.mdx @@ -1,137 +1,28 @@ --- -title: "Production Hardening & Operations" -description: "Production readiness checklist — replace secrets, configure TLS, set up managed data stores, run Postgres/ClickHouse/MinIO backups, and follow the upgrade runbook." +title: "Production" +description: "What to harden before a self-hosted Future AGI instance goes live" --- -## About +Everything past a local trial happens here. The default Docker Compose stack boots with placeholder secrets, no TLS, and compose-managed data stores. That's fine on a laptop. Before real traffic reaches the instance, work through the flow below in order, then keep each page as a runbook. -Run through this before exposing the stack to real users. Covers secrets, TLS, swapping in managed data stores, backup commands for Postgres/ClickHouse/MinIO, Prometheus monitoring, and the upgrade and rollback runbook. +## In this page -## Hardening checklist - -**Secrets** — replace all `CHANGEME` values before going live: - -```bash -openssl rand -hex 32 # SECRET_KEY, AGENTCC_INTERNAL_API_KEY -openssl rand -base64 24 # PG_PASSWORD, MINIO_ROOT_PASSWORD -``` - -**Runtime flags** in `.env`: -- `ENV_TYPE=prod` -- `FAST_STARTUP=false` -- `GRANIAN_WORKERS=` - -**TLS** — the frontend and backend don't terminate TLS. Put Caddy, nginx, or Traefik in front: - -``` -# Caddyfile (simplest — auto-issues Let's Encrypt certs) -app.yourcompany.com { reverse_proxy localhost:3000 } -api.yourcompany.com { reverse_proxy localhost:8000 } -``` - -After setting up TLS, set `VITE_HOST_API=https://api.yourcompany.com` in `.env` and rebuild: - -```bash -docker compose build frontend && docker compose up -d frontend -``` - -**Managed data stores** — for production, replace compose-managed services: - -| Replace | With | Change | -|---|---|---| -| `postgres` | RDS / Aurora / Cloud SQL | Set `PG_*` vars to managed endpoint | -| `clickhouse` | ClickHouse Cloud | Set `CH_HOST`, `CH_PORT`, etc. | -| `redis` | ElastiCache / Upstash | Set `REDIS_URL` | -| `minio` | AWS S3 | Set `S3_ENDPOINT_URL=https://s3.amazonaws.com` + AWS creds | - - -`code-executor` requires `privileged: true`. Run on EC2 / GCE instances — not Fargate or Cloud Run. - - -**Secrets manager** — use AWS Secrets Manager, HashiCorp Vault, or GCP Secret Manager instead of a plain `.env` file. - ---- - -## Backups - -### PostgreSQL - -```bash -# Backup -docker compose exec postgres \ - pg_dump -U futureagi -d futureagi --format=custom \ - > backup-$(date +%F).dump - -# Restore -docker compose exec -T postgres \ - pg_restore -U futureagi -d futureagi --clean --if-exists \ - < backup-2026-04-22.dump -``` - -Volumes: `future-agi_postgres-data` · `future-agi_clickhouse-data` · `future-agi_redis-data` · `future-agi_minio-data` · `future-agi_peerdb-catalog-data` · `future-agi_peerdb-minio-data` - -### ClickHouse - -```sql -BACKUP TABLE default.traces TO S3('s3://your-bucket/ch-backup/', 'KEY', 'SECRET'); -``` - -ClickHouse data can also be rebuilt from scratch by re-running PeerDB init since it replicates from Postgres. - -### MinIO - -```bash -mc alias set local http://localhost:9005 futureagi -mc alias set s3 https://s3.amazonaws.com -mc mirror local/ s3/your-bucket/ -``` - ---- - -## Monitoring - -Backend exposes Prometheus metrics at `http://localhost:8000/metrics`. Add a scraper: - -```yaml -# prometheus.yml -scrape_configs: - - job_name: futureagi - static_configs: - - targets: ['localhost:8000'] - metrics_path: /metrics -``` - -Key signals: backend error rate, Temporal workflow success/failure, Postgres WAL lag (PeerDB health), ClickHouse query latency, PeerDB mirror status at [localhost:3001](http://localhost:3001). - ---- - -## Upgrades - -```bash -git pull -docker compose build -docker compose up -d -``` - -Migrations run automatically. If a migration fails: `docker compose exec backend python manage.py migrate` - -If release notes mention PeerDB changes: `docker compose run --rm peerdb-init bash /setup.sh` - -**Rollback:** - -```bash -git log --oneline -5 -git checkout -docker compose build && docker compose up -d -``` - -## Next Steps +Production readiness for a self-hosted instance breaks into five steps. Do them in order the first time. - - Symptoms, causes, and fixes for common errors. + + The go-live pass: secrets, prod runtime flags, and managed data stores + + + Terminate TLS in front of the stack and lock down secrets + + + Back up and restore Postgres, ClickHouse, and MinIO + + + Scrape Prometheus metrics and watch the signals that matter - - Tune the LLM gateway, PeerDB mirrors, and Temporal workers. + + Pull a release, run migrations, and roll back safely diff --git a/src/pages/docs/self-hosting/production/backups-restore.mdx b/src/pages/docs/self-hosting/production/backups-restore.mdx new file mode 100644 index 00000000..f04c193d --- /dev/null +++ b/src/pages/docs/self-hosting/production/backups-restore.mdx @@ -0,0 +1,68 @@ +--- +title: "Backups & restore" +description: "Back up and restore the data stores behind a self-hosted instance" +--- + +A self-hosted instance keeps state in four stores: Postgres for application data, ClickHouse for observability records, MinIO for object storage, and Redis for cache and queues. This page covers backing up and restoring the three that hold durable data. Redis is a cache and doesn't need a backup. + +## Postgres + +Postgres holds the application data, so back it up on a schedule. Use the custom format so restores can run selectively: + +```bash +# Backup +docker compose exec postgres \ + pg_dump -U futureagi -d futureagi --format=custom \ + > backup-$(date +%F).dump + +# Restore +docker compose exec -T postgres \ + pg_restore -U futureagi -d futureagi --clean --if-exists \ + < backup-2026-04-22.dump +``` + +The Docker volumes that hold state: + +| Volume | Holds | +|---|---| +| `future-agi_postgres-data` | Postgres application data | +| `future-agi_clickhouse-data` | ClickHouse records | +| `future-agi_redis-data` | Redis cache | +| `future-agi_minio-data` | MinIO objects | +| `future-agi_peerdb-catalog-data` | PeerDB replication catalog | +| `future-agi_peerdb-minio-data` | PeerDB staging objects | + +## ClickHouse + +ClickHouse can back up straight to S3: + +```sql +BACKUP TABLE default.traces TO S3('s3://your-bucket/ch-backup/', 'KEY', 'SECRET'); +``` + + +ClickHouse is a replica of Postgres data, streamed through PeerDB. If you lose it, rebuild it from scratch by re-running PeerDB init rather than restoring a backup. The steps are in [Upgrades & rollback](/docs/self-hosting/production/upgrades-rollback). + + +## MinIO + +Mirror the MinIO bucket to S3 with the MinIO client: + +```bash +mc alias set local http://localhost:9005 futureagi +mc alias set s3 https://s3.amazonaws.com +mc mirror local/ s3/your-bucket/ +``` + +If you've already moved to [managed data stores](/docs/self-hosting/production/checklist), your provider's own backup tooling replaces these commands. + +## Dive deeper + + + + Watch store health and replication lag + + + Rebuild ClickHouse and roll back releases + + diff --git a/src/pages/docs/self-hosting/production/checklist.mdx b/src/pages/docs/self-hosting/production/checklist.mdx new file mode 100644 index 00000000..272d324e --- /dev/null +++ b/src/pages/docs/self-hosting/production/checklist.mdx @@ -0,0 +1,57 @@ +--- +title: "Checklist" +description: "The go-live pass before a self-hosted instance takes real traffic" +--- + +Run through this once before the stack is reachable by anyone else. It covers the three things that separate a laptop trial from a real deployment: replacing the shipped secrets, switching the backend into production mode, and swapping compose-managed data stores for managed ones. + +## Replace the shipped secrets + +The stack boots with `CHANGEME` placeholders. Replace every one before the instance is reachable, and generate each value rather than making one up: + +```bash +openssl rand -hex 32 # SECRET_KEY, AGENTCC_INTERNAL_API_KEY +openssl rand -base64 24 # PG_PASSWORD, MINIO_ROOT_PASSWORD +``` + + +`PG_PASSWORD` and `MINIO_ROOT_PASSWORD` are written to their volumes on first boot only. Set them before your first `docker compose up`. Changing them after the volume exists locks you out. The full field list is in [Environment variables](/docs/self-hosting/environment). + + +## Switch the backend to production mode + +Set these runtime flags before going live: + +| Variable | Go-live value | Why | +|---|---|---| +| `ENV_TYPE` | `prod` | Disables debug output and runs Django `check --deploy` | +| `FAST_STARTUP` | `false` | Always applies migrations on restart | +| `GRANIAN_WORKERS` | your CPU count | One worker per core, up from the default `1` | + +To tune the gateway, PeerDB, and Temporal workers, see [System configuration](/docs/self-hosting/configuration). + +## Move to managed data stores + +Compose-managed Postgres, ClickHouse, Redis, and MinIO are fine for a trial. For production, point the stack at managed services so data outlives the containers: + +| Replace | With | Set | +|---|---|---| +| `postgres` | RDS, Aurora, or Cloud SQL | `PG_*` to the managed endpoint | +| `clickhouse` | ClickHouse Cloud | `CH_HOST`, `CH_PORT`, and credentials | +| `redis` | ElastiCache or Upstash | `REDIS_URL` | +| `minio` | AWS S3 | `S3_ENDPOINT_URL` plus AWS credentials | + + +`code-executor` needs `privileged: true`, so it can't run on ECS Fargate or Cloud Run. Put it on an EC2 or GCE instance. The platform matrix is in [Requirements](/docs/self-hosting/requirements). + + +## Dive deeper + + + + Put TLS in front of the stack and move secrets into a manager + + + Set up backups before the instance holds real data + + diff --git a/src/pages/docs/self-hosting/production/monitoring.mdx b/src/pages/docs/self-hosting/production/monitoring.mdx new file mode 100644 index 00000000..cb23a7ce --- /dev/null +++ b/src/pages/docs/self-hosting/production/monitoring.mdx @@ -0,0 +1,46 @@ +--- +title: "Monitoring" +description: "Scrape a self-hosted instance and watch the signals that predict trouble" +--- + +The backend exposes Prometheus metrics, so any Prometheus-compatible stack can scrape it. This page covers wiring up the scrape and the handful of signals worth alerting on. + +## Scrape the backend + +The backend serves Prometheus metrics at `http://localhost:8000/metrics`. Add it as a scrape target: + +```yaml +# prometheus.yml +scrape_configs: + - job_name: futureagi + static_configs: + - targets: ['localhost:8000'] + metrics_path: /metrics +``` + +## Watch these signals + +| Signal | Why it matters | +|---|---| +| Backend error rate | The first sign a release or dependency broke | +| Temporal workflow success and failure | Failing workflows mean evals and background jobs are stuck | +| Postgres WAL lag | Rising lag means PeerDB replication is falling behind | +| ClickHouse query latency | Slow queries surface as a slow dashboard | +| PeerDB mirror status | The health of the Postgres to ClickHouse pipeline | + +PeerDB has its own console at [localhost:3001](http://localhost:3001) for mirror status and throughput. + + +Postgres WAL lag and PeerDB mirror status are the two to page on first. When ClickHouse drifts from Postgres, dashboards read stale before anything visibly breaks. + + +## Dive deeper + + + + Keep the stack current without downtime + + + Symptoms, causes, and fixes for common errors + + diff --git a/src/pages/docs/self-hosting/production/security-tls.mdx b/src/pages/docs/self-hosting/production/security-tls.mdx new file mode 100644 index 00000000..aa6d228b --- /dev/null +++ b/src/pages/docs/self-hosting/production/security-tls.mdx @@ -0,0 +1,59 @@ +--- +title: "Security & TLS" +description: "Terminate TLS in front of a self-hosted instance and lock down its secrets" +--- + +Neither the frontend nor the backend terminates TLS. In production you put a reverse proxy in front of the stack to handle certificates, then point the frontend at the HTTPS endpoint. This page covers both, plus where production secrets should live. + +## Terminate TLS with a reverse proxy + +Run Caddy, nginx, or Traefik in front of the stack. Caddy is the shortest path because it issues and renews Let's Encrypt certificates on its own: + +``` +# Caddyfile +app.yourcompany.com { reverse_proxy localhost:3000 } +api.yourcompany.com { reverse_proxy localhost:8000 } +``` + + + + Point the proxy at the frontend on `localhost:3000` and the backend on `localhost:8000`. The full port list is in [Requirements](/docs/self-hosting/requirements#ports-reference). + + + Set `VITE_HOST_API=https://api.yourcompany.com` in `.env`. This is a build-time value, so the frontend has to be rebuilt for it to take effect. + + + ```bash + docker compose build frontend && docker compose up -d frontend + ``` + + + + +`VITE_HOST_API` is baked in at build time, not read at runtime. If the browser still calls the old host after you change it, the frontend wasn't rebuilt. + + +## Keep secrets out of the compose file + +For anything past a single trial host, store secrets in a dedicated manager instead of a plain `.env`: + +- AWS Secrets Manager +- HashiCorp Vault +- GCP Secret Manager + +Rotate the `CHANGEME` values from the [Checklist](/docs/self-hosting/production/checklist) first, then move them into the manager and inject them at deploy time. + +## Isolate the code executor + +`code-executor` runs with `privileged: true` so it can sandbox evaluation code. Keep it on a host you control, an EC2 or GCE instance, never a managed-container platform that can't grant that flag. + +## Dive deeper + + + + Protect the data behind the proxy + + + Tune the gateway, PeerDB, and Temporal workers + + diff --git a/src/pages/docs/self-hosting/production/upgrades-rollback.mdx b/src/pages/docs/self-hosting/production/upgrades-rollback.mdx new file mode 100644 index 00000000..0e1b903d --- /dev/null +++ b/src/pages/docs/self-hosting/production/upgrades-rollback.mdx @@ -0,0 +1,59 @@ +--- +title: "Upgrades & rollback" +description: "Pull a new release, run migrations, and roll back when one goes wrong" +--- + +Upgrades are a git pull and a rebuild, and migrations run automatically on boot. This page covers the routine upgrade, the two cases that need a manual step, and how to roll back. + +## Upgrade to a new release + + + + ```bash + git pull + docker compose build + docker compose up -d + ``` + + + Database migrations run automatically on backend startup. If one fails, run it by hand: + ```bash + docker compose exec backend python manage.py migrate + ``` + + + When a release changes the replication setup, re-run init so ClickHouse stays in sync: + ```bash + docker compose run --rm peerdb-init bash /setup.sh + ``` + + + + +Because ClickHouse replicates from Postgres through PeerDB, re-running PeerDB init also rebuilds ClickHouse from scratch. That's the recovery path when the [ClickHouse store](/docs/self-hosting/production/backups-restore) is lost. + + +## Roll back a bad release + +Roll back to the previous commit and rebuild: + +```bash +git log --oneline -5 +git checkout +docker compose build && docker compose up -d +``` + + +Checking out older code does not undo a migration that already ran. If a release applied a migration you need to reverse, roll it back before you switch code, or restore Postgres from a backup. + + +## Dive deeper + + + + Symptoms, causes, and fixes for common errors + + + Where to get help when you're stuck + + diff --git a/src/pages/docs/self-hosting/support.mdx b/src/pages/docs/self-hosting/support.mdx new file mode 100644 index 00000000..38d69bd0 --- /dev/null +++ b/src/pages/docs/self-hosting/support.mdx @@ -0,0 +1,43 @@ +--- +title: "Support" +description: "Where to get help running a self-hosted Future AGI instance" +--- + +Running the open-source stack and hit something these pages don't cover? Here's where to reach the team and the community, and what to include so you get a useful answer fast. + +## Where to get help + + + + Ask the community and the team in the Future AGI Discord + + + Report a bug or request a feature on the open-source repo + + + +## Before you post + +A self-hosting question is easier to answer with the basics attached: + +- What you ran and what happened, with the exact error +- Output of `docker compose ps` so the team can see which service is down +- Logs from the failing service: `docker compose logs --tail=100` +- Your platform (Linux host, EC2, GCE) and whether you're on managed data stores + +Most self-hosting questions are already answered in [Troubleshooting & FAQs](/docs/self-hosting/troubleshooting). Check there first. + +## Commercial support + +For managed hosting, an SLA, or help with a production rollout, reach out at [sales@futureagi.com](mailto:sales@futureagi.com). + +## Dive deeper + + + + Symptoms, causes, and fixes for common errors + + + Harden the instance before it goes live + + From 53eb7ab2dbd43bb418c31f7d4649ca6621aa6230 Mon Sep 17 00:00:00 2001 From: Abhijai Srivastava Date: Fri, 3 Jul 2026 15:58:33 +0530 Subject: [PATCH 13/24] docs: rewrite Production pages against the real compose/deploy config Addresses Khushal's #705 review. Every claim re-grounded in the product repo: - Checklist: real dev-only defaults + deploy/docker-compose.production.yml ${VAR:?} guard, full required-secrets list; PG (first-boot) vs MinIO (every-boot); managed stores are edited in compose (hardcoded hosts), not .env; S3 via STORAGE_BACKEND - Backups: Redis is a cache (RabbitMQ holds the queue); pg_dump -T; futureagi_ volume prefix + full list; ClickHouse needs its own backup post-CH25 (spans don't return from PeerDB) - Monitoring: no /metrics endpoint exists; reworked around docker health, fi-collector :9464, PeerDB UI - Upgrades: peerdb-init needs no args; PeerDB init is not the ClickHouse recovery path - Support: correct Discord invite; dropped the backward-pointing footer - Nav: Production Overview child so /production is reachable --- src/lib/navigation.ts | 1 + .../production/backups-restore.mdx | 34 ++++++++-------- .../self-hosting/production/checklist.mdx | 40 ++++++++++++------- .../self-hosting/production/monitoring.mdx | 40 +++++++++---------- .../self-hosting/production/security-tls.mdx | 2 +- .../production/upgrades-rollback.mdx | 6 +-- src/pages/docs/self-hosting/support.mdx | 13 +----- 7 files changed, 69 insertions(+), 67 deletions(-) diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts index 3ad68081..db314c4d 100644 --- a/src/lib/navigation.ts +++ b/src/lib/navigation.ts @@ -72,6 +72,7 @@ export const tabNavigation: NavTab[] = [ { title: 'Production', items: [ + { title: 'Overview', href: '/docs/self-hosting/production' }, { title: 'Checklist', href: '/docs/self-hosting/production/checklist' }, { title: 'Security & TLS', href: '/docs/self-hosting/production/security-tls' }, { title: 'Backups & restore', href: '/docs/self-hosting/production/backups-restore' }, diff --git a/src/pages/docs/self-hosting/production/backups-restore.mdx b/src/pages/docs/self-hosting/production/backups-restore.mdx index f04c193d..5b0b257f 100644 --- a/src/pages/docs/self-hosting/production/backups-restore.mdx +++ b/src/pages/docs/self-hosting/production/backups-restore.mdx @@ -3,15 +3,15 @@ title: "Backups & restore" description: "Back up and restore the data stores behind a self-hosted instance" --- -A self-hosted instance keeps state in four stores: Postgres for application data, ClickHouse for observability records, MinIO for object storage, and Redis for cache and queues. This page covers backing up and restoring the three that hold durable data. Redis is a cache and doesn't need a backup. +A self-hosted instance keeps state in a few stores: Postgres for application data, ClickHouse for the observability records (spans and traces), and MinIO for object storage. Redis is a cache (sessions, locks, rate limits, pub/sub), so it rebuilds on its own and doesn't need a backup. RabbitMQ holds the task queue: losing it drops in-flight background jobs, so drain it before planned downtime rather than backing it up. ## Postgres -Postgres holds the application data, so back it up on a schedule. Use the custom format so restores can run selectively: +Postgres holds the application data, so back it up on a schedule. Use the custom format, and pass `-T` so `docker compose exec` doesn't allocate a TTY and mangle the binary dump: ```bash # Backup -docker compose exec postgres \ +docker compose exec -T postgres \ pg_dump -U futureagi -d futureagi --format=custom \ > backup-$(date +%F).dump @@ -21,28 +21,30 @@ docker compose exec -T postgres \ < backup-2026-04-22.dump ``` -The Docker volumes that hold state: +The named volumes that hold state. The compose project name is `futureagi`, so every volume is prefixed `futureagi_`: | Volume | Holds | |---|---| -| `future-agi_postgres-data` | Postgres application data | -| `future-agi_clickhouse-data` | ClickHouse records | -| `future-agi_redis-data` | Redis cache | -| `future-agi_minio-data` | MinIO objects | -| `future-agi_peerdb-catalog-data` | PeerDB replication catalog | -| `future-agi_peerdb-minio-data` | PeerDB staging objects | +| `futureagi_postgres-data` | Postgres application data | +| `futureagi_clickhouse-data` | ClickHouse spans and traces | +| `futureagi_minio-data` | MinIO objects | +| `futureagi_rabbitmq-data` | RabbitMQ task queue | +| `futureagi_redis-data` | Redis cache (rebuildable) | +| `futureagi_peerdb-catalog-data` | PeerDB replication catalog | +| `futureagi_peerdb-minio-data` | PeerDB staging objects | +| `futureagi_fi-collector-data` | fi-collector buffer | ## ClickHouse -ClickHouse can back up straight to S3: +ClickHouse is not just a replica anymore. Since the CH25 cutover (`CH25_DROP_LEGACY_CDC_CHAIN` defaults to `true`), the fi-collector writes `spans` straight to ClickHouse and Django dual-writes `traces`. PeerDB only rebuilds the tables it mirrors from Postgres, so if you lose ClickHouse the observability data does **not** come back from a PeerDB re-init. Back it up on its own: ```sql -BACKUP TABLE default.traces TO S3('s3://your-bucket/ch-backup/', 'KEY', 'SECRET'); +BACKUP DATABASE default TO S3('s3://your-bucket/ch-backup/', 'KEY', 'SECRET'); ``` - -ClickHouse is a replica of Postgres data, streamed through PeerDB. If you lose it, rebuild it from scratch by re-running PeerDB init rather than restoring a backup. The steps are in [Upgrades & rollback](/docs/self-hosting/production/upgrades-rollback). - + +Don't rely on PeerDB init to rebuild ClickHouse. It restores the mirrored Postgres tables, not the `spans` the collector writes directly. ClickHouse needs a real backup on its own schedule. + ## MinIO @@ -63,6 +65,6 @@ If you've already moved to [managed data stores](/docs/self-hosting/production/c Watch store health and replication lag
- Rebuild ClickHouse and roll back releases + Roll back releases without losing data
diff --git a/src/pages/docs/self-hosting/production/checklist.mdx b/src/pages/docs/self-hosting/production/checklist.mdx index 272d324e..370361be 100644 --- a/src/pages/docs/self-hosting/production/checklist.mdx +++ b/src/pages/docs/self-hosting/production/checklist.mdx @@ -3,19 +3,33 @@ title: "Checklist" description: "The go-live pass before a self-hosted instance takes real traffic" --- -Run through this once before the stack is reachable by anyone else. It covers the three things that separate a laptop trial from a real deployment: replacing the shipped secrets, switching the backend into production mode, and swapping compose-managed data stores for managed ones. +Run through this once before the stack is reachable by anyone else. Three things separate a laptop trial from a real deployment: -## Replace the shipped secrets +- Replace the dev-only secret defaults +- Bring the stack up with the production overlay, so it refuses to boot until those secrets are set +- Move the compose-managed data stores to managed services -The stack boots with `CHANGEME` placeholders. Replace every one before the instance is reachable, and generate each value rather than making one up: +## Replace the dev-only secrets + +The stack boots with dev-only placeholders baked into `docker-compose.yml`, values like `local-dev-only-not-for-production-replace-me`, and `futureagi` for the database passwords. It runs fine with them, which is the point on a laptop and the danger in production. + +What forces real secrets is the production overlay, `deploy/docker-compose.production.yml`. It re-binds each one with `${VAR:?}`, so the stack won't start until you've set them. Bring the stack up with that overlay and set, at minimum: + +- `SECRET_KEY` +- `AGENTCC_INTERNAL_API_KEY` +- `AGENTCC_ADMIN_TOKEN` +- `PG_PASSWORD` +- `MINIO_ROOT_PASSWORD` +- `RABBITMQ_USER` and `RABBITMQ_PASSWORD` +- `FRONTEND_URL` and `VITE_HOST_API` ```bash -openssl rand -hex 32 # SECRET_KEY, AGENTCC_INTERNAL_API_KEY -openssl rand -base64 24 # PG_PASSWORD, MINIO_ROOT_PASSWORD +openssl rand -hex 32 # SECRET_KEY, AGENTCC_INTERNAL_API_KEY, AGENTCC_ADMIN_TOKEN +openssl rand -base64 24 # PG_PASSWORD, MINIO_ROOT_PASSWORD, RABBITMQ_PASSWORD ``` -`PG_PASSWORD` and `MINIO_ROOT_PASSWORD` are written to their volumes on first boot only. Set them before your first `docker compose up`. Changing them after the volume exists locks you out. The full field list is in [Environment variables](/docs/self-hosting/environment). +`PG_PASSWORD` is baked into the Postgres volume on the **first** boot, so set it before your first `docker compose up`. `MINIO_ROOT_PASSWORD` is read from the environment on every boot, so that one you can change and restart. The full field list is in [Environment variables](/docs/self-hosting/environment). ## Switch the backend to production mode @@ -28,21 +42,19 @@ Set these runtime flags before going live: | `FAST_STARTUP` | `false` | Always applies migrations on restart | | `GRANIAN_WORKERS` | your CPU count | One worker per core, up from the default `1` | -To tune the gateway, PeerDB, and Temporal workers, see [System configuration](/docs/self-hosting/configuration). - ## Move to managed data stores -Compose-managed Postgres, ClickHouse, Redis, and MinIO are fine for a trial. For production, point the stack at managed services so data outlives the containers: +Compose-managed Postgres, ClickHouse, Redis, and MinIO are fine for a trial. For production, point the stack at managed services. The catch: the backend reads these hosts from **hardcoded values in the `backend` env block of `docker-compose.yml`** (`PG_HOST: postgres`, `CH_HOST: clickhouse`, `REDIS_URL: redis://redis:6379/0`, `S3_ENDPOINT_URL: http://minio:9000`), not from `.env`. Setting them in `.env` does nothing. You edit the compose file. -| Replace | With | Set | +| Replace | With | Edit in `docker-compose.yml` | |---|---|---| -| `postgres` | RDS, Aurora, or Cloud SQL | `PG_*` to the managed endpoint | -| `clickhouse` | ClickHouse Cloud | `CH_HOST`, `CH_PORT`, and credentials | +| `postgres` | RDS, Aurora, or Cloud SQL | `PG_HOST` / `PG_PORT` to the managed endpoint | +| `clickhouse` | ClickHouse Cloud | `CH_HOST` / `CH_PORT` and the credentials | | `redis` | ElastiCache or Upstash | `REDIS_URL` | -| `minio` | AWS S3 | `S3_ENDPOINT_URL` plus AWS credentials | +| `minio` | AWS S3 | `STORAGE_BACKEND: s3` and the S3 credentials | -`code-executor` needs `privileged: true`, so it can't run on ECS Fargate or Cloud Run. Put it on an EC2 or GCE instance. The platform matrix is in [Requirements](/docs/self-hosting/requirements). +`code-executor` runs with `privileged: true`, so it can't run on ECS Fargate or Cloud Run. Put it on an EC2 or GCE instance. The platform matrix is in [Requirements](/docs/self-hosting/requirements). ## Dive deeper diff --git a/src/pages/docs/self-hosting/production/monitoring.mdx b/src/pages/docs/self-hosting/production/monitoring.mdx index cb23a7ce..b17aad53 100644 --- a/src/pages/docs/self-hosting/production/monitoring.mdx +++ b/src/pages/docs/self-hosting/production/monitoring.mdx @@ -1,37 +1,35 @@ --- title: "Monitoring" -description: "Scrape a self-hosted instance and watch the signals that predict trouble" +description: "Watch a self-hosted instance with the health signals it actually exposes" --- -The backend exposes Prometheus metrics, so any Prometheus-compatible stack can scrape it. This page covers wiring up the scrape and the handful of signals worth alerting on. +The stack has no Prometheus `/metrics` endpoint yet (the fi-collector lists a metrics exporter as a TODO), so monitoring today is built from what the containers already expose: their Docker health checks, the fi-collector's admin health endpoint, and the PeerDB console. This page covers those and the signals worth watching. -## Scrape the backend +## Container health -The backend serves Prometheus metrics at `http://localhost:8000/metrics`. Add it as a scrape target: +Every service ships a Docker health check, so `docker compose ps` is the fastest read on what's up: -```yaml -# prometheus.yml -scrape_configs: - - job_name: futureagi - static_configs: - - targets: ['localhost:8000'] - metrics_path: /metrics +```bash +docker compose ps # STATUS shows healthy / unhealthy per service +docker stats # live CPU and memory per container ``` -## Watch these signals +Watch memory on `clickhouse` and the Temporal `worker` first. They're the resource drivers, and an OOM there is the most common cause of a stall. -| Signal | Why it matters | -|---|---| -| Backend error rate | The first sign a release or dependency broke | -| Temporal workflow success and failure | Failing workflows mean evals and background jobs are stuck | -| Postgres WAL lag | Rising lag means PeerDB replication is falling behind | -| ClickHouse query latency | Slow queries surface as a slow dashboard | -| PeerDB mirror status | The health of the Postgres to ClickHouse pipeline | +## fi-collector health -PeerDB has its own console at [localhost:3001](http://localhost:3001) for mirror status and throughput. +The fi-collector exposes an admin endpoint on `127.0.0.1:9464` (`FI_COLLECTOR_ADMIN_PORT`), which serves a health check. Hit it to confirm the collector is up and accepting spans: + +```bash +curl -s http://localhost:9464/healthz +``` + +## PeerDB replication + +The Postgres-to-ClickHouse pipeline has its own console at [localhost:3001](http://localhost:3001). Mirror status there tells you whether trace analytics are keeping up with Postgres. A mirror in anything other than `running` means the dashboard is reading stale. -Postgres WAL lag and PeerDB mirror status are the two to page on first. When ClickHouse drifts from Postgres, dashboards read stale before anything visibly breaks. +A Prometheus metrics exporter is on the fi-collector roadmap. When it lands, scrape it here. Until then, the checks above are what the stack actually exposes. ## Dive deeper diff --git a/src/pages/docs/self-hosting/production/security-tls.mdx b/src/pages/docs/self-hosting/production/security-tls.mdx index aa6d228b..5c66ccce 100644 --- a/src/pages/docs/self-hosting/production/security-tls.mdx +++ b/src/pages/docs/self-hosting/production/security-tls.mdx @@ -41,7 +41,7 @@ For anything past a single trial host, store secrets in a dedicated manager inst - HashiCorp Vault - GCP Secret Manager -Rotate the `CHANGEME` values from the [Checklist](/docs/self-hosting/production/checklist) first, then move them into the manager and inject them at deploy time. +Rotate the dev-only default secrets from the [Checklist](/docs/self-hosting/production/checklist) first, then move them into the manager and inject them at deploy time. ## Isolate the code executor diff --git a/src/pages/docs/self-hosting/production/upgrades-rollback.mdx b/src/pages/docs/self-hosting/production/upgrades-rollback.mdx index 0e1b903d..4c2e382b 100644 --- a/src/pages/docs/self-hosting/production/upgrades-rollback.mdx +++ b/src/pages/docs/self-hosting/production/upgrades-rollback.mdx @@ -22,15 +22,15 @@ Upgrades are a git pull and a rebuild, and migrations run automatically on boot. ``` - When a release changes the replication setup, re-run init so ClickHouse stays in sync: + When a release changes which Postgres tables are mirrored, re-run init. The container's entrypoint is already `bash /setup.sh`, so no arguments are needed: ```bash - docker compose run --rm peerdb-init bash /setup.sh + docker compose run --rm peerdb-init ``` -Because ClickHouse replicates from Postgres through PeerDB, re-running PeerDB init also rebuilds ClickHouse from scratch. That's the recovery path when the [ClickHouse store](/docs/self-hosting/production/backups-restore) is lost. +PeerDB init only rebuilds the tables it mirrors from Postgres. It does **not** restore the `spans` the fi-collector writes straight to ClickHouse, so it is not a recovery path for lost ClickHouse data. For that, restore from a [ClickHouse backup](/docs/self-hosting/production/backups-restore). ## Roll back a bad release diff --git a/src/pages/docs/self-hosting/support.mdx b/src/pages/docs/self-hosting/support.mdx index 38d69bd0..9ba30624 100644 --- a/src/pages/docs/self-hosting/support.mdx +++ b/src/pages/docs/self-hosting/support.mdx @@ -8,7 +8,7 @@ Running the open-source stack and hit something these pages don't cover? Here's ## Where to get help - + Ask the community and the team in the Future AGI Discord @@ -30,14 +30,3 @@ Most self-hosting questions are already answered in [Troubleshooting & FAQs](/do ## Commercial support For managed hosting, an SLA, or help with a production rollout, reach out at [sales@futureagi.com](mailto:sales@futureagi.com). - -## Dive deeper - - - - Symptoms, causes, and fixes for common errors - - - Harden the instance before it goes live - - From 07b23e7b19c6d95b2daf73f11b65c43e0d4770ec Mon Sep 17 00:00:00 2001 From: Abhijai Srivastava Date: Fri, 3 Jul 2026 16:27:06 +0530 Subject: [PATCH 14/24] docs: production overview themed card groups (no orphan) + fix monitoring card/claim - Split the overview into 'Before you go live' (2) and 'Operating it' (3) so no lone orphan card - Overview Monitoring card no longer promises Prometheus metrics (the page was reworked away from a non-existent /metrics) - fi-collector healthz confirms the collector is up, not that it's 'accepting spans' --- src/pages/docs/self-hosting/production.mdx | 11 +++++++++-- src/pages/docs/self-hosting/production/monitoring.mdx | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/pages/docs/self-hosting/production.mdx b/src/pages/docs/self-hosting/production.mdx index 5b0b2c5b..3689444b 100644 --- a/src/pages/docs/self-hosting/production.mdx +++ b/src/pages/docs/self-hosting/production.mdx @@ -7,7 +7,9 @@ Everything past a local trial happens here. The default Docker Compose stack boo ## In this page -Production readiness for a self-hosted instance breaks into five steps. Do them in order the first time. +Production readiness for a self-hosted instance breaks into five steps. Do them in order the first time, then keep each page as a runbook. + +**Before you go live** @@ -16,11 +18,16 @@ Production readiness for a self-hosted instance breaks into five steps. Do them Terminate TLS in front of the stack and lock down secrets + + +**Operating it** + + Back up and restore Postgres, ClickHouse, and MinIO - Scrape Prometheus metrics and watch the signals that matter + Watch the health signals the stack actually exposes Pull a release, run migrations, and roll back safely diff --git a/src/pages/docs/self-hosting/production/monitoring.mdx b/src/pages/docs/self-hosting/production/monitoring.mdx index b17aad53..e2b5498e 100644 --- a/src/pages/docs/self-hosting/production/monitoring.mdx +++ b/src/pages/docs/self-hosting/production/monitoring.mdx @@ -18,7 +18,7 @@ Watch memory on `clickhouse` and the Temporal `worker` first. They're the resour ## fi-collector health -The fi-collector exposes an admin endpoint on `127.0.0.1:9464` (`FI_COLLECTOR_ADMIN_PORT`), which serves a health check. Hit it to confirm the collector is up and accepting spans: +The fi-collector exposes an admin endpoint on `127.0.0.1:9464` (`FI_COLLECTOR_ADMIN_PORT`), which serves a health check. Hit it to confirm the collector is up: ```bash curl -s http://localhost:9464/healthz From 60d518cafe97f034b323993b012c3dc11ab0729c Mon Sep 17 00:00:00 2001 From: khushalsonawat Date: Mon, 6 Jul 2026 11:59:37 +0530 Subject: [PATCH 15/24] docs(self-hosting): address round-2 review on Production pages (#705) --- src/pages/docs/self-hosting/production.mdx | 2 +- src/pages/docs/self-hosting/production/monitoring.mdx | 2 +- src/pages/docs/self-hosting/production/security-tls.mdx | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/docs/self-hosting/production.mdx b/src/pages/docs/self-hosting/production.mdx index 3689444b..fa37559a 100644 --- a/src/pages/docs/self-hosting/production.mdx +++ b/src/pages/docs/self-hosting/production.mdx @@ -7,7 +7,7 @@ Everything past a local trial happens here. The default Docker Compose stack boo ## In this page -Production readiness for a self-hosted instance breaks into five steps. Do them in order the first time, then keep each page as a runbook. +Production readiness for a self-hosted instance breaks into five steps. Do them in order the first time. **Before you go live** diff --git a/src/pages/docs/self-hosting/production/monitoring.mdx b/src/pages/docs/self-hosting/production/monitoring.mdx index e2b5498e..6774fd9c 100644 --- a/src/pages/docs/self-hosting/production/monitoring.mdx +++ b/src/pages/docs/self-hosting/production/monitoring.mdx @@ -7,7 +7,7 @@ The stack has no Prometheus `/metrics` endpoint yet (the fi-collector lists a me ## Container health -Every service ships a Docker health check, so `docker compose ps` is the fastest read on what's up: +The data stores (Postgres, ClickHouse, Redis, RabbitMQ, MinIO, Temporal) ship Docker health checks; the application services just show `running`. Either way, `docker compose ps` is the fastest read on what's up: ```bash docker compose ps # STATUS shows healthy / unhealthy per service diff --git a/src/pages/docs/self-hosting/production/security-tls.mdx b/src/pages/docs/self-hosting/production/security-tls.mdx index 5c66ccce..772af2ac 100644 --- a/src/pages/docs/self-hosting/production/security-tls.mdx +++ b/src/pages/docs/self-hosting/production/security-tls.mdx @@ -20,17 +20,17 @@ api.yourcompany.com { reverse_proxy localhost:8000 } Point the proxy at the frontend on `localhost:3000` and the backend on `localhost:8000`. The full port list is in [Requirements](/docs/self-hosting/requirements#ports-reference). - Set `VITE_HOST_API=https://api.yourcompany.com` in `.env`. This is a build-time value, so the frontend has to be rebuilt for it to take effect. + Set `VITE_HOST_API=https://api.yourcompany.com` in `.env`. The frontend container reads it on start and writes it into `config.js`, so no rebuild is needed. - + ```bash - docker compose build frontend && docker compose up -d frontend + docker compose up -d frontend ``` -`VITE_HOST_API` is baked in at build time, not read at runtime. If the browser still calls the old host after you change it, the frontend wasn't rebuilt. +`VITE_HOST_API` is applied when the frontend container starts, not at build time. If the browser still calls the old host after you change it, the container wasn't recreated: rerun `docker compose up -d frontend`. ## Keep secrets out of the compose file From 83ae3ab19f7db591877a0046d18c9e9166610c37 Mon Sep 17 00:00:00 2001 From: Abhijai Srivastava Date: Mon, 29 Jun 2026 20:03:36 +0530 Subject: [PATCH 16/24] docs: add self-hosting system configuration page TH-6328 --- .../self-hosting/configuration/system.mdx | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 src/pages/docs/self-hosting/configuration/system.mdx diff --git a/src/pages/docs/self-hosting/configuration/system.mdx b/src/pages/docs/self-hosting/configuration/system.mdx new file mode 100644 index 00000000..11be1545 --- /dev/null +++ b/src/pages/docs/self-hosting/configuration/system.mdx @@ -0,0 +1,143 @@ +--- +title: "System Configuration" +description: "Configure the moving parts beyond .env — the LLM gateway config.yaml with provider keys, PeerDB Postgres-to-ClickHouse replication mirrors, and Temporal worker concurrency." +--- + +## Introduction + +A few parts of the stack are configured outside `.env`: the LLM gateway needs a `config.yaml` listing its providers, PeerDB needs its replication mirrors running, and Temporal workers can be tuned for throughput. This page covers all three. Set your secrets and provider keys in [Environment Variables](/docs/self-hosting/configuration/environment) first — the config here references them. + +## LLM Gateway + +The gateway is a Go proxy that routes every model call the platform makes. It reads a `config.yaml` that lists which providers it may use and which models each exposes. + + +Model calls fail until this file exists. The gateway ships with `config.example.yaml` (OpenAI enabled) but **not** a live `config.yaml` — you create one in the steps below. + + + + +```bash +cp futureagi/agentcc-gateway/config.example.yaml \ + futureagi/agentcc-gateway/config.yaml +``` + + + +Edit `config.yaml` — uncomment the providers you want and reference their keys with `${VAR}` interpolation. Set the matching keys (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, …) in `.env`. See the provider examples below. + + + +Point the gateway volume at your `config.yaml` in `docker-compose.yml`: + +```yaml +volumes: + - ./futureagi/agentcc-gateway/config.yaml:/app/config.yaml:ro +``` + +```bash +docker compose up -d --force-recreate gateway +``` + + + + +`config.yaml` is gitignored and holds live API keys. Treat it as a secret — never commit it. + + +### Provider Examples + + + +```yaml +providers: + openai: + api_key: "${OPENAI_API_KEY}" + api_format: "openai" + models: [gpt-4o, gpt-4o-mini] + + anthropic: + api_key: "${ANTHROPIC_API_KEY}" + api_format: "anthropic" + models: [claude-opus-4-5, claude-sonnet-4-5] + + gemini: + api_key: "${GOOGLE_API_KEY}" + api_format: "gemini" + models: [gemini-2.0-flash, gemini-1.5-pro] +``` + + +```yaml +providers: + bedrock: + api_key: "${AWS_SECRET_ACCESS_KEY}" + api_format: "bedrock" + region: "${AWS_REGION}" + access_key: "${AWS_ACCESS_KEY_ID}" + models: [anthropic.claude-3-5-sonnet-20241022-v2:0] +``` + + +```yaml +providers: + vertex: + base_url: "https://us-central1-aiplatform.googleapis.com" + api_key: "${GOOGLE_ACCESS_TOKEN}" + api_format: "gemini" + headers: + x-gcp-project: "${GCP_PROJECT_ID}" + x-gcp-location: "us-central1" + models: [gemini-2.0-flash-001] +``` + +Vertex uses a Bearer token, not a static API key. Rotate `GOOGLE_ACCESS_TOKEN` with a sidecar that calls `gcloud auth print-access-token`. + + + +For routing rules, rate limits, caching, and the full config reference, see [Agent Command Center → Self-Hosted](/docs/command-center/deployment/self-hosted). + +## PeerDB Replication + +PeerDB continuously replicates Postgres tables into ClickHouse (change-data-capture) so trace and eval analytics stay fast. It runs on its own — the only thing you typically touch is a first-boot timing fix. + + +**First-boot timing.** `peerdb-init` runs the moment the stack starts, sometimes before Django has finished its migrations. If mirrors show "not started" in the PeerDB UI, re-run init once the backend is up: + +```bash +docker compose logs -f backend # wait for "Application startup complete" +docker compose run --rm peerdb-init bash /setup.sh # re-run init +``` + + +Verify at [http://localhost:3001](http://localhost:3001) — mirrors should move to `running` within seconds. Re-run the same init command after any upgrade that changes replicated tables. + +## Temporal Workers + +Temporal runs the platform's background jobs and evaluation pipelines. How those jobs are distributed across workers depends on one flag. + +**All-queue (default).** One worker polls every task queue. Controlled by `TEMPORAL_ALL_QUEUES=true` in `.env`. This is the right setup for most self-hosted deployments. + +**Per-queue (dev overlay).** Six dedicated workers, one per queue, brought up by the [dev overlay](/docs/self-hosting/install#dev-overlay): + +| Service | Queue | Typical concurrency | +|---|---|---| +| `worker-default` | `default` | 100 | +| `worker-tasks-s` | `tasks_s` | 200 | +| `worker-tasks-l` | `tasks_l` | 50 | +| `worker-tasks-xl` | `tasks_xl` | 10 | +| `worker-trace-ingestion` | `trace_ingestion` | 100 | +| `worker-agent-compass` | `agent_compass` | 50 | + +Tune throughput with `TEMPORAL_MAX_CONCURRENT_ACTIVITIES` and `TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASKS` in `.env`. The Temporal UI is available in dev mode at [http://localhost:8085](http://localhost:8085). + +## Dive Deeper + + + + Hardening, backups, and monitoring before going live. + + + Fixes for gateway, PeerDB, and Temporal errors. + + From 90fc401d0b5414e6aaededc221cd66274f5e57cd Mon Sep 17 00:00:00 2001 From: Abhijai Srivastava Date: Wed, 1 Jul 2026 17:22:16 +0530 Subject: [PATCH 17/24] docs: align frontmatter with review standards - title: sentence case to match sidebar label - description: remove em-dash, shorten to single purpose line TH-6329 --- src/pages/docs/self-hosting/configuration/system.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/docs/self-hosting/configuration/system.mdx b/src/pages/docs/self-hosting/configuration/system.mdx index 11be1545..a32cafa5 100644 --- a/src/pages/docs/self-hosting/configuration/system.mdx +++ b/src/pages/docs/self-hosting/configuration/system.mdx @@ -1,6 +1,6 @@ --- -title: "System Configuration" -description: "Configure the moving parts beyond .env — the LLM gateway config.yaml with provider keys, PeerDB Postgres-to-ClickHouse replication mirrors, and Temporal worker concurrency." +title: "System configuration" +description: "Configure the LLM gateway, PeerDB replication, and Temporal workers for your self-hosted instance." --- ## Introduction From d775e2d27e50edbf9d6936eac734c656ee94ddb6 Mon Sep 17 00:00:00 2001 From: Abhijai Srivastava Date: Thu, 2 Jul 2026 22:18:30 +0530 Subject: [PATCH 18/24] docs: address Khushal's review on system configuration - Fix /configure -> /configuration link typo on the overview (prose + card) - Rename System configuration opener from Introduction to In this page - Drop em-dashes across the page (intro + gateway/PeerDB sections) - Fix gateway config path: agentcc-gateway is at repo root, not under futureagi/ --- src/pages/docs/self-hosting.mdx | 4 ++-- .../self-hosting/configuration/system.mdx | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/pages/docs/self-hosting.mdx b/src/pages/docs/self-hosting.mdx index e2dd80c7..28ddd24f 100644 --- a/src/pages/docs/self-hosting.mdx +++ b/src/pages/docs/self-hosting.mdx @@ -36,7 +36,7 @@ postgres ──── PeerDB CDC ──── clickhouse (continuous replicati - **Workflow**: `temporal` - **CDC**: PeerDB (continuous Postgres → ClickHouse replication) -Everything runs on your machines; nothing leaves your network. The full service-by-service breakdown lives in [Configure](/docs/self-hosting/configure) +Everything runs on your machines; nothing leaves your network. The full service-by-service breakdown lives in [Configure](/docs/self-hosting/configuration). ## Deployment options @@ -49,7 +49,7 @@ Everything runs on your machines; nothing leaves your network. The full service- ## Where to go next - + System requirements, prerequisites, environment variables, and setup diff --git a/src/pages/docs/self-hosting/configuration/system.mdx b/src/pages/docs/self-hosting/configuration/system.mdx index a32cafa5..99aba25c 100644 --- a/src/pages/docs/self-hosting/configuration/system.mdx +++ b/src/pages/docs/self-hosting/configuration/system.mdx @@ -3,28 +3,28 @@ title: "System configuration" description: "Configure the LLM gateway, PeerDB replication, and Temporal workers for your self-hosted instance." --- -## Introduction +## In this page -A few parts of the stack are configured outside `.env`: the LLM gateway needs a `config.yaml` listing its providers, PeerDB needs its replication mirrors running, and Temporal workers can be tuned for throughput. This page covers all three. Set your secrets and provider keys in [Environment Variables](/docs/self-hosting/configuration/environment) first — the config here references them. +A few parts of the stack are configured outside `.env`: the LLM gateway needs a `config.yaml` listing its providers, PeerDB needs its replication mirrors running, and Temporal workers can be tuned for throughput. This page covers all three. Set your secrets and provider keys in [Environment Variables](/docs/self-hosting/configuration/environment) first, since the config here references them. ## LLM Gateway The gateway is a Go proxy that routes every model call the platform makes. It reads a `config.yaml` that lists which providers it may use and which models each exposes. -Model calls fail until this file exists. The gateway ships with `config.example.yaml` (OpenAI enabled) but **not** a live `config.yaml` — you create one in the steps below. +Model calls fail until this file exists. The gateway ships with `config.example.yaml` (OpenAI enabled) but **not** a live `config.yaml`. You create one in the steps below. ```bash -cp futureagi/agentcc-gateway/config.example.yaml \ - futureagi/agentcc-gateway/config.yaml +cp agentcc-gateway/config.example.yaml \ + agentcc-gateway/config.yaml ``` -Edit `config.yaml` — uncomment the providers you want and reference their keys with `${VAR}` interpolation. Set the matching keys (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, …) in `.env`. See the provider examples below. +Edit `config.yaml`: uncomment the providers you want and reference their keys with `${VAR}` interpolation. Set the matching keys (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, …) in `.env`. See the provider examples below. @@ -32,7 +32,7 @@ Point the gateway volume at your `config.yaml` in `docker-compose.yml`: ```yaml volumes: - - ./futureagi/agentcc-gateway/config.yaml:/app/config.yaml:ro + - ./agentcc-gateway/config.yaml:/app/config.yaml:ro ``` ```bash @@ -42,7 +42,7 @@ docker compose up -d --force-recreate gateway -`config.yaml` is gitignored and holds live API keys. Treat it as a secret — never commit it. +`config.yaml` is gitignored and holds live API keys. Treat it as a secret. Never commit it. ### Provider Examples @@ -99,7 +99,7 @@ For routing rules, rate limits, caching, and the full config reference, see [Age ## PeerDB Replication -PeerDB continuously replicates Postgres tables into ClickHouse (change-data-capture) so trace and eval analytics stay fast. It runs on its own — the only thing you typically touch is a first-boot timing fix. +PeerDB continuously replicates Postgres tables into ClickHouse (change-data-capture) so trace and eval analytics stay fast. It runs on its own. The only thing you typically touch is a first-boot timing fix. **First-boot timing.** `peerdb-init` runs the moment the stack starts, sometimes before Django has finished its migrations. If mirrors show "not started" in the PeerDB UI, re-run init once the backend is up: @@ -110,7 +110,7 @@ docker compose run --rm peerdb-init bash /setup.sh # re-run init ``` -Verify at [http://localhost:3001](http://localhost:3001) — mirrors should move to `running` within seconds. Re-run the same init command after any upgrade that changes replicated tables. +Verify at [http://localhost:3001](http://localhost:3001). Mirrors should move to `running` within seconds. Re-run the same init command after any upgrade that changes replicated tables. ## Temporal Workers From 19305bb8af5205bf805389642000f4089a0aadfd Mon Sep 17 00:00:00 2001 From: khushalsonawat Date: Mon, 6 Jul 2026 12:05:02 +0530 Subject: [PATCH 19/24] docs(self-hosting): point sidebar at nested System configuration; fix stale install link (#695 review) --- src/lib/navigation.ts | 2 +- src/pages/docs/self-hosting/configuration/system.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts index db314c4d..47908b1a 100644 --- a/src/lib/navigation.ts +++ b/src/lib/navigation.ts @@ -66,7 +66,7 @@ export const tabNavigation: NavTab[] = [ title: 'Configuration', items: [ { title: 'Environment variables', href: '/docs/self-hosting/environment' }, - { title: 'System configuration', href: '/docs/self-hosting/configuration' }, + { title: 'System configuration', href: '/docs/self-hosting/configuration/system' }, ] }, { diff --git a/src/pages/docs/self-hosting/configuration/system.mdx b/src/pages/docs/self-hosting/configuration/system.mdx index 99aba25c..b28489dc 100644 --- a/src/pages/docs/self-hosting/configuration/system.mdx +++ b/src/pages/docs/self-hosting/configuration/system.mdx @@ -118,7 +118,7 @@ Temporal runs the platform's background jobs and evaluation pipelines. How those **All-queue (default).** One worker polls every task queue. Controlled by `TEMPORAL_ALL_QUEUES=true` in `.env`. This is the right setup for most self-hosted deployments. -**Per-queue (dev overlay).** Six dedicated workers, one per queue, brought up by the [dev overlay](/docs/self-hosting/install#dev-overlay): +**Per-queue (dev overlay).** Six dedicated workers, one per queue, brought up by the [dev overlay](/docs/self-hosting/installation#other-ways-to-run-it): | Service | Queue | Typical concurrency | |---|---|---| From e7b9b84967798d609836236fee50701158ebd202 Mon Sep 17 00:00:00 2001 From: Abhijai Srivastava Date: Thu, 2 Jul 2026 16:26:48 +0530 Subject: [PATCH 20/24] docs: add self-hosting environment variables page Complete .env reference under Configuration, self-reviewed against the docs review guide (review-docs-like-khushal). TH-6328 --- .../configuration/environment.mdx | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/pages/docs/self-hosting/configuration/environment.mdx b/src/pages/docs/self-hosting/configuration/environment.mdx index 6e38d95d..ee472b99 100644 --- a/src/pages/docs/self-hosting/configuration/environment.mdx +++ b/src/pages/docs/self-hosting/configuration/environment.mdx @@ -1,9 +1,9 @@ --- title: "Environment variables" -description: "Complete .env reference for a self-hosted Future AGI instance." +description: "Complete .env reference for a self-hosted Future AGI instance" --- -## Introduction +## In this page Every setting the stack reads at boot comes from a single `.env` file in the repo root. This page is the complete reference, grouped by what each variable does. The stack boots fine with the shipped defaults. The only thing you *must* change before sharing the instance is the `CHANGEME` secrets. @@ -24,10 +24,10 @@ Replace every `CHANGEME` in this group before anyone else can reach the instance | `SECRET_KEY` | `openssl rand -hex 32` | Django sessions, CSRF, password reset | | `PG_PASSWORD` | `openssl rand -base64 24` | PostgreSQL auth | | `MINIO_ROOT_PASSWORD` | `openssl rand -base64 24` | MinIO object storage auth | -| `AGENTCC_INTERNAL_API_KEY` | `openssl rand -hex 32` | Backend ↔ gateway shared secret | +| `AGENTCC_INTERNAL_API_KEY` | `openssl rand -hex 32` | Backend and gateway shared secret | -`PG_PASSWORD` is written to the Postgres volume on **first boot only**. If you change it after the volume exists, authentication fails — see the fix in [Troubleshooting](/docs/self-hosting/troubleshooting). Set it before your first `docker compose up`. +`PG_PASSWORD` is written to the Postgres volume on **first boot only**. If you change it after the volume exists, authentication fails. See the fix in [Troubleshooting](/docs/self-hosting/troubleshooting). Set it before your first `docker compose up`. ## Database Credentials @@ -43,37 +43,37 @@ Replace every `CHANGEME` in this group before anyone else can reach the instance ## Ports -Every service port is configurable. The full table — defaults, what each binds to, and exposure scope — lives in [Requirements → Ports and Firewall](/docs/self-hosting/requirements#ports-and-firewall), so you can plan firewall rules in one place. +Every service port is configurable. The full table (defaults, what each binds to, and exposure scope) lives in [Requirements](/docs/self-hosting/requirements#ports-reference), so you can plan firewall rules in one place. ## Backend Runtime | Variable | Default | Description | |---|---|---| -| `ENV_TYPE` | `development` | `development` · `staging` · `prod`. Prod mode disables debug output and enables `check --deploy`. | -| `FAST_STARTUP` | `false` | Skip migrations on restart (dev only). Always `false` in production. | -| `GRANIAN_WORKERS` | `1` | ASGI worker processes. Set to your CPU count in production. | -| `GRANIAN_THREADS` | `2` | Threads per worker. | -| `ENABLE_GRPC` | `true` | Enable the gRPC endpoint. | -| `ENABLE_HTTP` | `true` | Enable the HTTP/REST endpoint. | +| `ENV_TYPE` | `development` | One of `development`, `staging`, or `prod`. Prod mode disables debug output and enables `check --deploy` | +| `FAST_STARTUP` | `false` | Skip migrations on restart (dev only). Always `false` in production | +| `GRANIAN_WORKERS` | `1` | ASGI worker processes. Set to your CPU count in production | +| `GRANIAN_THREADS` | `2` | Threads per worker | +| `ENABLE_GRPC` | `true` | Enable the gRPC endpoint | +| `ENABLE_HTTP` | `true` | Enable the HTTP/REST endpoint | ## Temporal Worker | Variable | Default | Description | |---|---|---| -| `TEMPORAL_NAMESPACE` | `default` | Temporal namespace. | -| `TEMPORAL_ALL_QUEUES` | `true` | Single worker polls all queues. Set `false` and use the dev overlay for per-queue workers. | -| `TEMPORAL_MAX_CONCURRENT_ACTIVITIES` | `50` | Max concurrent activity tasks. | -| `TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASKS` | `50` | Max concurrent workflow tasks. | +| `TEMPORAL_NAMESPACE` | `default` | Temporal namespace | +| `TEMPORAL_ALL_QUEUES` | `true` | Single worker polls all queues. Set `false` and use the dev overlay for per-queue workers | +| `TEMPORAL_MAX_CONCURRENT_ACTIVITIES` | `50` | Max concurrent activity tasks | +| `TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASKS` | `50` | Max concurrent workflow tasks | -Tuning guidance lives in [System Configuration → Temporal Workers](/docs/self-hosting/configuration/system#temporal-workers). +Tuning guidance lives in [System configuration](/docs/self-hosting/configuration/system#temporal-workers). ## LLM Gateway | Variable | Default | Description | |---|---|---| -| `AGENTCC_INTERNAL_API_KEY` | `CHANGEME` | **Must change.** The backend authenticates gateway calls with this shared secret. | +| `AGENTCC_INTERNAL_API_KEY` | `CHANGEME` | **Must change.** The backend authenticates gateway calls with this shared secret | -Setting a key here is only half the job — the gateway also needs a `config.yaml` listing the providers it may route to. See [System Configuration → LLM Gateway](/docs/self-hosting/configuration/system#llm-gateway). +Setting a key here is only half the job. The gateway also needs a `config.yaml` listing the providers it may route to. See [System configuration](/docs/self-hosting/configuration/system#llm-gateway). ## LLM Provider Keys @@ -105,26 +105,26 @@ These are baked into the JavaScript bundle at Vite build time. Changing them req | Variable | Default | Description | |---|---|---| -| `VITE_HOST_API` | `http://localhost:8000` | Backend URL as seen by the browser. In production, use your public backend URL. | -| `VITE_ENVIRONMENT` | `development` | Frontend analytics and feature flags. | +| `VITE_HOST_API` | `http://localhost:8000` | Backend URL as seen by the browser. In production, use your public backend URL | +| `VITE_ENVIRONMENT` | `development` | Frontend analytics and feature flags | ## Optional | Variable | Default | Description | |---|---|---| -| `RECAPTCHA_ENABLED` | `false` | Enable reCAPTCHA on registration. | -| `RECAPTCHA_SECRET_KEY` | — | reCAPTCHA v2/v3 server-side key. | -| `VITE_GOOGLE_SITE_KEY` | — | reCAPTCHA client-side key (requires a frontend rebuild). | -| `FUTURE_AGI_CLOUD_API_KEY` | — | Enterprise-tier Cloud features only. Leave blank for the open-source build. | -| `FUTURE_AGI_CLOUD_API_URL` | `https://api.futureagi.com` | Do not change. | +| `RECAPTCHA_ENABLED` | `false` | Enable reCAPTCHA on registration | +| `RECAPTCHA_SECRET_KEY` | `(none)` | reCAPTCHA v2/v3 server-side key | +| `VITE_GOOGLE_SITE_KEY` | `(none)` | reCAPTCHA client-side key (requires a frontend rebuild) | +| `FUTURE_AGI_CLOUD_API_KEY` | `(none)` | Enterprise-tier Cloud features only. Leave blank for the open-source build | +| `FUTURE_AGI_CLOUD_API_URL` | `https://api.futureagi.com` | Do not change | -## Dive Deeper +## Dive deeper - - Point the LLM gateway at your providers and set up PeerDB mirrors. + + Point the LLM gateway at your providers and set up PeerDB mirrors - - Harden the instance before exposing it to users. + + Harden the instance before exposing it to users From 7f042d5f5f9e2d0e18ba4e8d10c48b8b57519ed4 Mon Sep 17 00:00:00 2001 From: khushalsonawat Date: Mon, 6 Jul 2026 12:11:52 +0530 Subject: [PATCH 21/24] docs(self-hosting): point sidebar at nested Environment variables; retire flat page (#704) --- src/lib/navigation.ts | 2 +- .../docker-compose-quickstart.mdx | 4 +- .../docs/self-hosting/docker-compose.mdx | 4 +- src/pages/docs/self-hosting/environment.mdx | 118 ------------------ src/pages/docs/self-hosting/installation.mdx | 2 +- .../self-hosting/production/checklist.mdx | 2 +- src/pages/docs/self-hosting/requirements.mdx | 2 +- 7 files changed, 8 insertions(+), 126 deletions(-) delete mode 100644 src/pages/docs/self-hosting/environment.mdx diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts index db314c4d..dc85bfb5 100644 --- a/src/lib/navigation.ts +++ b/src/lib/navigation.ts @@ -65,7 +65,7 @@ export const tabNavigation: NavTab[] = [ { title: 'Configuration', items: [ - { title: 'Environment variables', href: '/docs/self-hosting/environment' }, + { title: 'Environment variables', href: '/docs/self-hosting/configuration/environment' }, { title: 'System configuration', href: '/docs/self-hosting/configuration' }, ] }, diff --git a/src/pages/docs/cookbook/self-hosting/docker-compose-quickstart.mdx b/src/pages/docs/cookbook/self-hosting/docker-compose-quickstart.mdx index 58c7fb85..5a368dc5 100644 --- a/src/pages/docs/cookbook/self-hosting/docker-compose-quickstart.mdx +++ b/src/pages/docs/cookbook/self-hosting/docker-compose-quickstart.mdx @@ -68,7 +68,7 @@ MAILGUN_DOMAIN=mg.your-domain.com If you don't have Mailgun, skip this. You can still create a user and set a password via the Django shell in [Step 4](#step-4). -See [Environment Variables](/docs/self-hosting/environment) for the full list of knobs. +See [Environment Variables](/docs/self-hosting/configuration/environment) for the full list of knobs. @@ -199,7 +199,7 @@ docker compose down -v Full deployment modes (full stack, dev overlay, frontend-only) - + Every secret, port, and runtime flag the stack reads diff --git a/src/pages/docs/self-hosting/docker-compose.mdx b/src/pages/docs/self-hosting/docker-compose.mdx index 1ce057d7..c039421e 100644 --- a/src/pages/docs/self-hosting/docker-compose.mdx +++ b/src/pages/docs/self-hosting/docker-compose.mdx @@ -23,7 +23,7 @@ First boot builds from source (~10–15 min). When the backend logs `Application - **Backend API** — [http://localhost:8000](http://localhost:8000) - **PeerDB UI** — [http://localhost:3001](http://localhost:3001) · `peerdb` / `peerdb` -Replace `CHANGEME` secrets in `.env` before sharing the instance with others. See [Environment Variables](/docs/self-hosting/environment). +Replace `CHANGEME` secrets in `.env` before sharing the instance with others. See [Environment Variables](/docs/self-hosting/configuration/environment). --- @@ -112,7 +112,7 @@ docker compose run --rm peerdb-init bash /setup.sh ## Next Steps - + Configure secrets, ports, and runtime flags in `.env`. diff --git a/src/pages/docs/self-hosting/environment.mdx b/src/pages/docs/self-hosting/environment.mdx deleted file mode 100644 index 0967ef80..00000000 --- a/src/pages/docs/self-hosting/environment.mdx +++ /dev/null @@ -1,118 +0,0 @@ ---- -title: "Self-Hosting Environment Variables" -description: "Full .env reference for self-hosted Future AGI — secrets, database credentials, runtime flags, LLM provider keys, email, and frontend build-time configuration." ---- - -## About - -Reference for every environment variable the stack reads from `.env`. Grouped by purpose: secrets, database credentials, runtime flags, LLM provider keys, email, and frontend build-time config. - -```bash -cp .env.example .env -``` - -The stack boots fine with defaults. Replace `CHANGEME` secrets before sharing with others. - -## Required secrets - -| Variable | Generate with | Used by | -|---|---|---| -| `SECRET_KEY` | `openssl rand -hex 32` | Django sessions, CSRF, password reset | -| `PG_PASSWORD` | `openssl rand -base64 24` | PostgreSQL auth | -| `MINIO_ROOT_PASSWORD` | `openssl rand -base64 24` | MinIO object storage auth | -| `AGENTCC_INTERNAL_API_KEY` | `openssl rand -hex 32` | Backend ↔ gateway shared secret | - -## Database credentials - -| Variable | Default | Notes | -|---|---|---| -| `PG_USER` | `futureagi` | PostgreSQL username | -| `PG_PASSWORD` | `CHANGEME` | **Must change** | -| `PG_DB` | `futureagi` | PostgreSQL database name | -| `MINIO_ROOT_USER` | `futureagi` | MinIO username | -| `MINIO_ROOT_PASSWORD` | `CHANGEME` | **Must change** | -| `CH_USE_REPLICATED_ENGINES` | `false` | `true` only for multi-node ClickHouse | - -## Ports - -All configurable. See [Requirements → Ports reference](/docs/self-hosting/requirements#ports-reference) for the full table with defaults and exposure scope. - -## Backend runtime - -| Variable | Default | Description | -|---|---|---| -| `ENV_TYPE` | `development` | `development` · `staging` · `prod` — prod mode disables debug output, enables `check --deploy` | -| `FAST_STARTUP` | `false` | Skip migrations on restart (dev only). Always `false` in production. | -| `GRANIAN_WORKERS` | `1` | ASGI worker processes. Set to CPU count in production. | -| `GRANIAN_THREADS` | `2` | Threads per worker. | -| `ENABLE_GRPC` | `true` | Enable gRPC endpoint. | -| `ENABLE_HTTP` | `true` | Enable HTTP/REST endpoint. | - -## Temporal worker - -| Variable | Default | Description | -|---|---|---| -| `TEMPORAL_NAMESPACE` | `default` | Temporal namespace. | -| `TEMPORAL_ALL_QUEUES` | `true` | Single worker polls all queues. Set `false` + use dev overlay for per-queue workers. | -| `TEMPORAL_MAX_CONCURRENT_ACTIVITIES` | `50` | Max concurrent activity tasks. | -| `TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASKS` | `50` | Max concurrent workflow tasks. | - -## LLM gateway - -| Variable | Default | Description | -|---|---|---| -| `AGENTCC_INTERNAL_API_KEY` | `CHANGEME` | **Must change.** Backend authenticates gateway calls with this. | - -## LLM provider keys - -Leave blank for providers you're not using. - -| Variable | Provider | -|---|---| -| `OPENAI_API_KEY` | OpenAI | -| `ANTHROPIC_API_KEY` | Anthropic | -| `GOOGLE_API_KEY` | Google Gemini | -| `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_REGION` | AWS Bedrock + S3 | - -## Email (Mailgun) - -Required for email-based sign-up and password reset. Without these, create users via the Django shell — see [User Management](/docs/self-hosting/user-management). - -| Variable | Description | -|---|---| -| `MAILGUN_API_KEY` | Mailgun private API key | -| `MAILGUN_SENDER_DOMAIN` | Verified Mailgun sending domain | -| `DEFAULT_FROM_EMAIL` | `From:` address for outbound emails | -| `SERVER_EMAIL` | Django admin error emails | - -## Frontend build-time - - -These are baked into the JS bundle at Vite build time. Changing them requires rebuilding: `docker compose build frontend` - - -| Variable | Default | Description | -|---|---|---| -| `VITE_HOST_API` | `http://localhost:8000` | Backend URL as seen by the browser. In production: your public backend URL. | -| `VITE_ENVIRONMENT` | `development` | Frontend analytics and feature flags. | - -## Optional - -| Variable | Default | Description | -|---|---|---| -| `RECAPTCHA_ENABLED` | `false` | Enable reCAPTCHA on registration. | -| `RECAPTCHA_SECRET_KEY` | — | reCAPTCHA v2/v3 server-side key. | -| `VITE_GOOGLE_SITE_KEY` | — | reCAPTCHA client-side key (requires frontend rebuild). | -| `FUTURE_AGI_CLOUD_API_KEY` | — | EE-tier Cloud features only. Leave blank for OSS. | -| `FUTURE_AGI_CLOUD_API_URL` | `https://api.futureagi.com` | Do not change. | - -## Next Steps - - - - Set up LLM gateway providers and PeerDB mirrors. - - - Hardening checklist for exposing the stack to users. - - diff --git a/src/pages/docs/self-hosting/installation.mdx b/src/pages/docs/self-hosting/installation.mdx index 1b8cffd4..9bc66c6d 100644 --- a/src/pages/docs/self-hosting/installation.mdx +++ b/src/pages/docs/self-hosting/installation.mdx @@ -131,7 +131,7 @@ For a frontend-only deploy, set `VITE_HOST_API` to the backend URL the browser c ## Dive deeper - + Set provider keys, secrets, and runtime flags in `.env` diff --git a/src/pages/docs/self-hosting/production/checklist.mdx b/src/pages/docs/self-hosting/production/checklist.mdx index 370361be..281fd201 100644 --- a/src/pages/docs/self-hosting/production/checklist.mdx +++ b/src/pages/docs/self-hosting/production/checklist.mdx @@ -29,7 +29,7 @@ openssl rand -base64 24 # PG_PASSWORD, MINIO_ROOT_PASSWORD, RABBITMQ_PASSWORD ``` -`PG_PASSWORD` is baked into the Postgres volume on the **first** boot, so set it before your first `docker compose up`. `MINIO_ROOT_PASSWORD` is read from the environment on every boot, so that one you can change and restart. The full field list is in [Environment variables](/docs/self-hosting/environment). +`PG_PASSWORD` is baked into the Postgres volume on the **first** boot, so set it before your first `docker compose up`. `MINIO_ROOT_PASSWORD` is read from the environment on every boot, so that one you can change and restart. The full field list is in [Environment variables](/docs/self-hosting/configuration/environment). ## Switch the backend to production mode diff --git a/src/pages/docs/self-hosting/requirements.mdx b/src/pages/docs/self-hosting/requirements.mdx index 4e0ce3be..0d1e1dd5 100644 --- a/src/pages/docs/self-hosting/requirements.mdx +++ b/src/pages/docs/self-hosting/requirements.mdx @@ -90,7 +90,7 @@ In production, only the frontend and backend ports should be internet-facing, an Clone, configure, and run the full stack. - + Set secrets and tune runtime flags before first boot. From cc4575220f966fc2de19ad90a6cbf8feee832ca0 Mon Sep 17 00:00:00 2001 From: khushalsonawat Date: Mon, 6 Jul 2026 12:21:30 +0530 Subject: [PATCH 22/24] docs(self-hosting): address review on Requirements; repoint ports anchor links (#696) --- .../configuration/environment.mdx | 2 +- .../self-hosting/production/security-tls.mdx | 2 +- src/pages/docs/self-hosting/requirements.mdx | 22 +++++++++++++++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/pages/docs/self-hosting/configuration/environment.mdx b/src/pages/docs/self-hosting/configuration/environment.mdx index ee472b99..e978151e 100644 --- a/src/pages/docs/self-hosting/configuration/environment.mdx +++ b/src/pages/docs/self-hosting/configuration/environment.mdx @@ -43,7 +43,7 @@ Replace every `CHANGEME` in this group before anyone else can reach the instance ## Ports -Every service port is configurable. The full table (defaults, what each binds to, and exposure scope) lives in [Requirements](/docs/self-hosting/requirements#ports-reference), so you can plan firewall rules in one place. +Every service port is configurable. The full table (defaults, what each binds to, and exposure scope) lives in [Requirements](/docs/self-hosting/requirements#network-ports), so you can plan firewall rules in one place. ## Backend Runtime diff --git a/src/pages/docs/self-hosting/production/security-tls.mdx b/src/pages/docs/self-hosting/production/security-tls.mdx index 772af2ac..51239b2a 100644 --- a/src/pages/docs/self-hosting/production/security-tls.mdx +++ b/src/pages/docs/self-hosting/production/security-tls.mdx @@ -17,7 +17,7 @@ api.yourcompany.com { reverse_proxy localhost:8000 } - Point the proxy at the frontend on `localhost:3000` and the backend on `localhost:8000`. The full port list is in [Requirements](/docs/self-hosting/requirements#ports-reference). + Point the proxy at the frontend on `localhost:3000` and the backend on `localhost:8000`. The full port list is in [Requirements](/docs/self-hosting/requirements#network-ports). Set `VITE_HOST_API=https://api.yourcompany.com` in `.env`. The frontend container reads it on start and writes it into `config.js`, so no rebuild is needed. diff --git a/src/pages/docs/self-hosting/requirements.mdx b/src/pages/docs/self-hosting/requirements.mdx index f23aa952..2589a712 100644 --- a/src/pages/docs/self-hosting/requirements.mdx +++ b/src/pages/docs/self-hosting/requirements.mdx @@ -58,7 +58,14 @@ sudo usermod -aG docker $USER # log out and back in ``` -Install [Docker Desktop for Windows](https://docs.docker.com/desktop/setup/install/windows-install/) with the WSL 2 backend, then set the memory limit in WSL, not Docker's UI: add `memory=8GB` under a `[wsl2]` section in `%UserProfile%\.wslconfig` and run `wsl --shutdown` to apply. The **Settings → Resources** sliders apply only to the Hyper-V backend. +Install [Docker Desktop for Windows](https://docs.docker.com/desktop/setup/install/windows-install/) with the WSL 2 backend, then set the memory limit in WSL, not Docker's UI (the **Settings → Resources** sliders apply only to the Hyper-V backend): +```powershell +# add to %UserProfile%\.wslconfig +[wsl2] +memory=8GB +# then apply: +wsl --shutdown +``` @@ -74,7 +81,7 @@ Future AGI runs on any host that allows **privileged containers**. The `code-exe | Google Cloud Run | No | Same | | Render / Railway / Fly.io | No | Managed platforms block privileged mode | -Helm/Kubernetes and air-gapped install are on the roadmap. Docker Compose is the supported path today. +Helm/Kubernetes support is on the roadmap. Docker Compose is the supported path today. ## Network ports @@ -98,3 +105,14 @@ Make sure these host ports are free before you install, or remap any that collid | PeerDB UI | `3001` | `0.0.0.0` | `PEERDB_UI_PORT` | The data stores (Postgres, ClickHouse, Redis, MinIO, Temporal) bind to `127.0.0.1`; the application services bind to `0.0.0.0`. PeerDB server and UI only run when you enable the CDC stack with `COMPOSE_PROFILES=full`, so those two ports are only in use in that mode. + +## Dive deeper + + + + Clone the repo and bring the stack up with `./bin/install` + + + Set provider keys, secrets, and runtime flags in `.env` + + From 7315d203ac518b3f303d3d3008fc0f7fbd224c3e Mon Sep 17 00:00:00 2001 From: khushalsonawat Date: Mon, 6 Jul 2026 12:29:14 +0530 Subject: [PATCH 23/24] docs: restore observe pages and components reverted by branch history; redirect retired env page --- .../docs/observe/llm-tracing-overview.webp | Bin 0 -> 194806 bytes src/components/CodeCopyButtons.astro | 1 + src/components/docs/Mermaid.astro | 60 +++++++ src/components/docs/Steps.astro | 54 +------ src/lib/navigation.ts | 18 ++- src/lib/redirects.ts | 1 + src/pages/docs/observe/concepts/spans.mdx | 43 +++++ src/pages/docs/observe/concepts/traces.mdx | 44 ++++++ src/pages/docs/observe/index.mdx | 62 ++++---- src/pages/docs/observe/quickstart.mdx | 147 ++++++++++++++++++ src/pages/docs/tracing/concepts/index.mdx | 4 +- src/plugins/vite-docs-transform.mjs | 1 + src/styles/global.css | 67 ++++++++ 13 files changed, 419 insertions(+), 83 deletions(-) create mode 100644 public/images/docs/observe/llm-tracing-overview.webp create mode 100644 src/components/docs/Mermaid.astro create mode 100644 src/pages/docs/observe/concepts/spans.mdx create mode 100644 src/pages/docs/observe/concepts/traces.mdx create mode 100644 src/pages/docs/observe/quickstart.mdx diff --git a/public/images/docs/observe/llm-tracing-overview.webp b/public/images/docs/observe/llm-tracing-overview.webp new file mode 100644 index 0000000000000000000000000000000000000000..81015fc86526517dbd60549103141c0e66e83fc6 GIT binary patch literal 194806 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 z z!rNVcFWzuRM5Gr=4YxDid0+4iquM&5t{4A1Pzs317_Io}(%fN)(T5UPkqzP*0}58K zmX{-u!(bbb9KP~SK=XPFAWDzfBP>pV5rI zy=S;@0w~kr2<$A8el<3iemb^NHSWy=!O)3uK}m9>5-HYDxe~(Rb`Qej_9PdRRmQpzzr`+c0RC zT)mZCLa0{fU`vMRBv=aol<*O}X*pfkp_SF}yJr&3x>9+)^O%gA`dpbhy{B4`N8|JF zD`jkeugu1G(5hoFfyX&&;iDke!(n~$nGjv2NqK_cwZC*8r1>gj(55FZvJ(5>n{-@s zQOmsjFB5y(l#?FZ<0+2j{;lJeO>9cr93ji?2}G`_-`TQ2Xbo@Qx%Cu{f4;*sAL^AF8@V>4mDhtvu}1IYd9~B&RO5lT`Z^;N zJ`M3}9qY!OM2m*LjtR3;y=!jkCVZEn!BS76jsvuTIkSHnOcq~pnBNIV;ydZV91VY? zZBB^)=8t35)uJ-m3a8LTPNOB5d;kOq$S#7gx{=~M6Z%$KBGznr%1>9DQhYNC!&zk{ zI}Zf&b{v(pvpLe8#{*ut>wCXNGVDG{d5jCyPtBD#W)`Q;D?+v{gTATd2V{h>Nz)PI znzKsA6mIGx_~Wyx@>O_RmBi}->N!+Vhig6+C~jpfYI{0mrFkTLpq`s0ZX%A&!+g1w z`<+Q|T)*j4f?mTr58K**UBmCaWZ3f%#vc( zR9c3?!LYkJ|3lr9>H0Zd_Zy7IK&SwsSbnLG?iV}WF&Qes;*okf_N!PH<4g(TtG_Ji z*lkS!rve=3kwjaQRCpan$3eX~ETT#LWi_mh0^9r4fMq3;5R_{lk7BtWvUCU+A8j4! z$kr{>Y-sq~Q@0HyrWV4u_w~LhWK;DJVlA-W;_0bN*eIMl7&@rmxpM3KM3>juPR`V9 zpeXAns0SZas#9knJQPVbRR2H;;xGi2XNt?H2h1gH@~-EKK^U0IO-O1YN$XA}<(sqM zu0(>*YH!7i|HS2d*=BhiHVtngK2cwl=YiOsOX0=pu_-qxgHhP12*W&G1!}# z))Vk@!>ULw#d&{K`C4JYEUl+lU;#68lDDq8(~8S={so*bza;%ji?s8LQI{T80~{IR z>KrzN43EBz^)vivQtZHe0eSgDKsuL2onx0bElIzKx1RqsB0y~0P5wPvDe$Ni4d2CB_O@TV(1!v{haFRmB5}2<{|H5W%aNM?ay!mCwjKJuuY9FttxKD#D3~)@ zkCRbDgy69f!yGirS;f^m+E4L<0}ERkHgCRB;$~iz14yD}kgBtCF*$V)tncYV(`d9a z0jI1Vr7i0Wi4MAX4dFy|GuSLbsB1E8pb+m}f;Uo)V*0`ss* z6E6Jy?t@_e6>s16tq88$QqanoO13k;=-0eUDB{v(1FQ=Nlh&aEzvhDv6>m>6y3g_2 z$=bV(KFN{|k8Ct^ddtWTa9`&o#E4}bRU>`;JDfko!tWErD?_%;VE`JCw`OD^5IAAZ zgaS4a<8pQ4yS_+=c1P=#N00+;>V<0O0$$wUUdla#N-xYG@l1$oz->v-A3l22>$oU7 zydnvNEL*%oQ|g^i6)(#H)(ik1`Lo28oDoxqV(k18y&dr}$Wh|MC6R&GR|f#ZZRh;6 zvA=T}pOnV{loI7BqbUqh16Ld;iXOiJfOkgS87rV}P-hOa02tfm4K9wr&Yk51-K$5< zseI4#N3>C36`h56dnaDw-?{4dxCk>e9O2d|sJSm+X>#qkc4PI??x@~Oq;cE5l%zeK(lJJY8+oKhu_+;x^Vc=3ye!Di@Jd|(`>sl&6=0nA5?Pr z{kX5O$pn@=%ike)BVy7T^E@ErQ%VX~u>>dACrEJerGSFQBb4Y1SUWmJ>dL#?>+4W! zffnEv|JHoK=p!lUI1-5Qg~7`WfQ@n51t-|Hj`bq%?aZ0fuspmLvAa5xb7B(aHxVy; z!26)9UVz7z7a%UJ7;B$rYfZpMb8=q?*rn`W&s{9`J{9g<>EW)QgHydqe-Ck@(UllKfg49FpF{o(L&2IfvlN%D+@)rNge!!{@XFkzg?aixlS70#*6$}U%UlUwA9PlHv> zwqvjyyG3FVBTuBZDLo zlMmiVdpDm00BoGf6f5n(&ahyLk;(s1)Mg$c{HLOg9g?c0g5+Zjz+Glor%feVQFw56 zrWBOdF~(wm{#7=9-J(adGN|SN@1ap9D0!JL7!0m6u>%ST`1`8O*(|GEBQ};?2A>K+n$Q@_6JQA zhmf=Hr61Dt`ObW!K>H`kftq&B(JTKsI!ou%I}hVS8mazkHoV^Yj(hZI?=T<3!ebFL z5+P0LXrTi{lH%XxPQFIII5f9tR_1y(czgYYa3igLx;*-m?OKGADUwAxOu^PhEZvl}oAF^OM?yE;LL` zi8X)@_9XpoQ#&tTAIUXj^42{H`s15e5&6Y`&Ifff#TK@s4emk_HDIz)l zmbw*Aac^X?CAl(X&?*kfFbqgdZEyR>qMw*7iPhMTdVM<` z{;ZBT0FcTTf6@ZnVCHG(Or$bqkP?d1uIOllikxk3{AV@w(It+;^#6H0h{wsIHm-SwSCW;tX^sFgFrk#CNO4^ zXgkJijh79F!SuDSa+x09G|cStjnLS|>OOp!@Wg!n!%S=w^`0cbSc}MObdJnom*9CV z1sPNXvq-7^W= zU0`7b`hX!IosKbBeg1Q8ZZuP8ZtmgaYJ67r;7#put{QRcnC0%)G*;2y1>ZExrsgQk zQrm=}%Vr+{sBf|$r@ zYg8GqNrzY=4~1gs*-?M2>?@s$gcR=l#=nMJ`&#oyXkfR=69nt&gje3*s;K?U@l~v) z2&msW1f#Dz5(Z!ESOj5Xkp6pz@ejn8r057{kGUA)1wo>~D)Hpg8<028)EOlUPO8pS*j41XBLq+$RKu z8@il5U8^vL9s})ij(U}lu23M5=3jmLo*YaDE2GweYJE*SiUxorn^>h;&sBn@^6H+j z!T$b=_?l4B?av5iu=X2qxWBc@jWkT+dnqXVG&+qH8BSAAAG%V2^{h` z?HMpa60Q^bfk%H>&mO~?COvlR!U{`-c+yj(%UeiTNyTy)oI9EmrNV3>-Mx7_*=T$o zy$@bwiL)WaTj>zr$^&mjAT=tgw!}0zcO3bl-WvVrVKRqn*NgKy>_7|Zo#MDlLjG3i zKMErvZ`zA7nS3VjR6?(I`vBvm;9Ms{PPKCW4gdo(1v85&A0gF36x#ArU31$*g+APw z`QHkGrWF4SV`UZue64yl#nR@B9Wk&s9lCuBz8kW{jE&AGhT8FxL#o?`Y}njJqy>SA zO)F>?QWNGR#crDphPe^CLFEtFdqIm+Ii1!3Rr}ntBZ7}GfljA&^tkku|Ky--XXZ;E z&#Q@!RmBQAdyCHJbEhExG z@7SavYq-zmu%M#u^m>y-yp{-;zE+4(g*`4bmGsSV769-NTuESArt(xSRxGdgU@@0! zRXPZM*!0<-e8z5qKbD}hPiKtc0LiKG-C$YPw|;O4$v9m+`T+PXv!2#(GQiKTr`6-E zizzYLZJ1ibj6n$B2yWc_rcUeNd_beZBto%Ss5uTr9^jOOh316d6813)LuoA2Ic$=4 ziv+BF7XS%}n}2QfS_uz}VopM$L`_~P95o~7c>{Ez0+jiw--NF+P*jZkRTO^_&iL`# zpY*votk~_v1DFMPA*ab2(c$*=BsNe4EA2<+*c^S6NSLhd-~`JhfJx5-Oo;fkRrj}6 z=Y!_6Z$tX(#d}Czo)wqVaE2`w*LPWlE+Y@j#eP>L&>S4j)*JBMnD@fFgyAnd5TeoQ z-vA-*yDYwQ@1gxI(gQZs3RMkygP*vA*_uv0=XDTCU@!}`Y??AzA#CwYmc}hf5^9Wn z*+v6r`?s<)6n|hmJ)oep53~@Mi#C3|hLz(@hg3-z@p`qgFnrS+It>{1r|P$jb9+Q# z9VtG$%0D_h1T*aXK!x$6P2r}TT@Lo*ljEGvLp}}i)()J~Y(>Zp8}wjQ=Ypl<(ZU(Q zsk+lfQ||MFE*2(p09=xn4L5jMjU*Qn^a$=XraclzCjt3yn?LHnlEJ|1ZS~ztF_wB= zEjDgpwK-&d{7ue-1ONk7N?k%%Lc(D39jo`EBPw6SJ;R=OV!{UiyS{MssZVj?tL?zU zYSHvW95u!1W?;z0K55Zizqt{v>PoLG&c0RkZR7qBA{ZM|Yi(H^4f8RG+dLF`?$!uIG(MTDA=CdSYvowzvP78LnPwhjW_s8&C?J(; zwr3vV6L45^p3oee^!#Ol=yr;y(8sFx6E@GOcQE~WYL|%_O%p-au~RYuhl;zCcU#^3 z&diK0jhEX#01XdtD|1|oCt~g)XxWqioOQ*hT&L6T!ph8`wxie9=OBPy%RY&j!cmjl zdu9JQn0QAdj66_w=-(#~x~|!I)0J(bg1h^$Jq7~D46sd9M9bmuYlqA-UM+CZ>iSf# zO9_M8R}C@^sH%_DU2`FqB8JL3=aCChx!ona>Uq)K;rXlGYj1T~Vn}>rXkGNux5yEN z%nJqe-EC1Z1WTmw;~QLTS}0dBm=xFl@=F3}KY;_2R>QRK%=ScYaVq)YoXtmVX=_9! zYKPjw`r*e1H1xmXbfOu{l&p4m2Xb4(s4n3;RLws`3X?TvT;XfO#WyqmE!QD_L}Z8f z{dDu_tp0Xmv~GqzoEIgKzL}6*Y9&;Zy-B7HzA9zZ_@?-(HOuH{oo8~YlhE|Bd40A% zwuyXz`zX~%mc>v?<|})G-vKB{b58(ayt|w?LlWEiD)i1C${*9DySiLFoAPU)D}r=_ z9T4s(JT)|@<$PfBgF&$7N&l=Xq5S6#{cwLyW-nsYM~FS~A&LBy-g~~TFiEWaV%t(u z8FRGGVJH3#yZ_dOP$^~=JD&U3*WKsooJQLgjwV6snd{eKqqnilgzc5%9l?j1@}2(~ zgj@qqJBZ>~B2T7AvngF1g0-ryJ4p2LD%O;pBMkbdc^m{c_CTMgmzsuleHpZcLaYL` zVl+6&I3_mnouqg2+f5{68{=h&cz0*#Bsg!arp`{LN?;Y{6o3;YK)d>SgiOXpM5qs`#N;8$yDmK~=MX1`g zZeT?<{OTTm*>O895&ybaFoqPLD~#O$KQO{nv*~ljNNY+9ogywt&oDXy*wF?Tvs;2N z?vp&#?8#n>86pD`J3XO0Unc*04VthQQmZJA*H3X(1^?MeF!(>dGX)|MdG;XH+6GAd8MvR0GmliJvl^I1-43syU@3>s2nWSV0|B9s@`J zKmDv?hnlK8?0$^DUVL$)?AEtj{XX5sgip|97yU69aAYeEV^UR_w z(W8?tdnyPfjKq5VyM5;rN$M@)=y27bpd0tx5usqfSQQ>a?_}M}(z{xd@&3$hlH{dy zwoD!rQ(k-5=4vDi5OH^l#aNLT2>aUFJNkv76~keNYg9Kwzf?9dVhpJdNtNVjK2K(` z!0@2>YxPcJ+47VUpqaU?7)>`IM9eUa)=r|!9UD~4nW3RUHgSX^o?x2 z!wECm70p3-x`^TYvp?sZx!x_<+p{5nDu0c+N}uZq+ZP(h?*{>eEcGuIVhevk}CtTk4qk^LtokAa#CmX|Tm1cUin^VIzA*Glj$UB^+?59}7QpzIrR=r;suFeP!cKn9`x-1EZX zL#Mmo>%+D9cPT$xc~AK;)~XfbE`Q8fqM1w_+nH|PU<;!(&423}-W6m-(e%$HYX70| z8S?v1G9^3=wc~M}75dLzjS9Ov{+GM9YwPEwd1IrdL<)-|(A*|%tU)AwXEfrtKNsfS zO36Q+0ChEtmmYNnBF;Cn#JXmG;b(NT5C!h?e2w>;YW*z3jWMijZPBq_N#+Tj?!2hB zEM?f#&}~uv8&=T-*VcIV=dI0AoGIrF%Q_|E301M$8J(r%VHK;-jrKv$Gh>Q_oXS#`p4l9p5vFqyOas|_MQWPnnW^K^KRUxTmNJo z_#z43&NPR_Nq~4PZSCdc3fEcHGed0OM7&Zbz756RuRwi*6b_t)X~{jfJiTqGX2_VD z4AN)<&%Z<_I2nwh26cV)MKggf-3n|z#%RtVR~fb^QjJW{Qy|80R|tuHi^#aQQuF! z>xio3y-US?M(!X$ts~j3ME3t1{DGeSr4BwSxI-jPfOx6t84(bSH{LL{#pFA{bkw7I ziS?hsPeiH66_obe5dWEuOU6lkE(YQVj|#$#0_r`gH07iDf7XIXD_NsccQ`pvJ)h}Uze$JAcYXNzLJO2on)lr64((IBCPa9Hvji7PGc^M^fG)nZM&Y6%Uu zba@ka9@2?O$CWGpxx|prz}T($PsLPMj)bD#Y8&vRKXe7h+IxM7y-pZ~rIM=DtlsOz zH8BiofHQKo)MDYNb~}f?m`*&P@eDtn{}Sa5Fq>52M_d+~&w=Qxg$HV32H&znoAQHR_2;y(`dkj z^)KXG%lDnCv!RD}Uxf0Vyb)t)ovIvja@okELCHBI6&Y>1SP6K?II^&&Bn?Z1fDII? zM?EJ|U#vW@8^-%TTRyV>1YFm@p1NMgqcQXi?hcJ67>xOgx%5@*{gK*2`f?Yz%-y0(!d85Ouvb3h$k^BbOI3u&lmBjRV7dg`4=il;K> zD#f(HbaT|lCBI_uGbk`(uf;Q$$*jkdmW9+wAu>JRVaJaHIBhFif&P<-WNvwAhqUe# zmx-7Z;FJ>q7(OolL{;TsrPyxap03$*6IhY0+?T(ZfTWISZ2pzJ=M4yYPg$C41hsdp z5P)`prt$S|{h8N6(NF}s-&yw7K7wvT%!&d4246f$o%yO62<1L*&@eo!viD0%ga4V2 z8@q=IYEAH#S#0o|KAh0j6dV0Q-z`10r;*ZKBzl6KdYJk)41fdq_;upRC_x8kW{osvvKVE>Cw!7@)9Xm>>4aac`%6MeHcC-UDNCv3Hbk#gi%KKw7`+WXdJ9 z3-K91Xv5Lni9j*oac-@_yRF)FGd>Vsn$e%60Q1A~3FnHo=~e`$OEQ0Y0K%e1rK{@r zYQ4`?R+s{no9J@;?56CkiqVb7*9!QTAj`?~(iGYOJzpcyZUUuXF&P}PeKyTeD-_*%o**$z_57FZ^YM$h5hnq@kR&|9M{qAZnk~gq!^0q0t?^ zyOgj&{Aqe3nme%-t?a4shuy}Q^oW9Iw+aBjpRhMk<;47E%S|5gccZL)4VXdNH8LU* zFJt@hy1BCn6ZtE?7AoI<_?Zz4#!M{GX%$oJG1!rZn2${ZN1sj~w!lzJhRxj#tk?Zh zBZ{g`y*T@~M$VGw*Mox1ZHMNQ5BL~0=uh4M9R|j2ot=Zgc!koURhF-&NvpEM5#1*> z>q2T*^LfWwC=k23Opgyns9UJS-vFhUnzqu*HoF~!yblbgIrESh@YYG$bek7@s(ff$ zosm>tz>4N-Be7^&8YM8OADlhAiwS3ygs+|!Lp1C3RbKdJ-&yfd$}C^8{`$K^xyuo> zzc{k5c!)^cn#_&9`z(F`fdnFX);fg8jurCAFkD{9807Di2+m5n-x&zcvZhXOKOj`4 z=aPMICIOxg%UB2fj+>1sp=~PfVZq9KuwX!$AofY}(uV0jbsCeS)J=IC%ymkHA8$>S-a%@n5y&He!h}d2eL}m2n4ws#PN`U+vW}97NP{&s5}}f zlw(<%&<*^{L?26>58F|Y;OCS5^!%ra9)Jdz-sgY_0A>g&k#g3bktxO{S5mATi&Dc5 zWYC54GT-s?Ns>`dT7`6QG(}ou|0hXSi|4qukVCdo{Ny&IL1Hk2C&m;pNeirLSSy5W z5ubCuq9H91$~D+)W%?;*0SM(uy2SwT0oVa(L>;=8WaYOof?=T*r@;6=KGhpLYKsdCt2+D5D*Q+YABo$5nS?b|EkhO~NK@AH^fmoc z!oKuZD#;E?xc#^+-#=k+v;5D-8jDWf7+Hg0#h~zlmaq0_6fI7PpoAr4s_0zOeqVekAj&w8WHA?QFgA}7?jA0-u;?VH z1NEp+K-hz|0D3edOvNeE7Js)>Co&^X-Mo^J9?McU_`?3ic#!=_UCFDfivOr_w3w`K zQ09XcG22YRZtOSaXrz`E@}=vT#gLwV|2b4L6LNoVFlA$3oq2D-6)=$M2OBi}V}!joZkg zK&r~m6_W~!At@BI#U^5i6&t!e-HFKdz;`4w0f7WcQY2T1jLc<3JpTE0KQzA_2dQSF zwk`PH)th#f_~jf7jefvDH&9xiQsp?wH^71og@U`YftcS58l~W$PzRQfg#p3lMF%~bkpdomrlbhKQyC#Bv}UjqA|dqiCk+Qs12g7 zX zlR<8e=QZqOS>?kE`q(@Uh&P*`8Z&RUruJB zz7$ef(qH-RQryKt<$v=UWXO9}^~%H9-lEH_V_IGcJd7VJsL+Z0?4eUP%>zwmA5N5p zKX33uGnQ@13ARSmkyx}ek_&y&E6?4qKgNwUCd)vdUPC2@Ne;O|^hYUhtT51Ab;z1=-lPHL<5mf4DF_z-W zlahI^$EL3w!>EeQE()R;Ia`&gZhL^9C`rcInc(fnfubU{;O91SMg0uWM25j=QRu_! zA4J9L(tORostHXS>nMcZX;h{!S?;2S>*6KBk1n8MgQWVML3+XzSr_ff{|91aIru1X zys%O?`u}&>`I-*@{c)X;X8yN4R3ezvuv^4Hlz&f^C;k_rwiqu5P6So)S#RgTbBYIm zdSaA1^W0A+1)z!2r}>%6JnB(3Yl|?1uL)H8cPXCy+KYmDzSp+D0{ys}%{~UA1UYAo z^8Z4-5V#*Zl2@h^{tq=9=YXcN48}`BpVt2|vvgBduqCXP)V#TYLg3MxKCV$c<$FG8MU*`f0PKvY$Lj}aw`DEFYddFwXL@k28@M3ZLbE13XLPv+h5 zKy4Csr*H$$}rPq(^HCK{ND&xCjT$QjyNv|4isg{d0*Gz%Rf&5 zjpP^&=K0^OazIn%FN<^41=Qmj)>aV+KU1hopEBHq^;boUg72L`MfwT<8$qp#|AqKp zlKnq&%YRAsKl|XnB>QhB`+v`5#;vXhNZDv~2XeZWyW}IUX_+UeSROjvyo5ZbY~2Pb zr0OiFX_o9qrcl9C_Do1-o2`uS9wCRAc>efob8Mf#4@io|Lw>18RBM&SCI}9vKByVW zHKPn#p}NOuh21ZWdZXtlVkv74S?bMO&JmN4*waNBv3mkE7zj{fdJl8o0&%_~Teg%lsU4%ku=YqzMP3jFt6Jev9AOB%Y}|)qyi8oe zrg`$66#tPxtQP9~EZYrWNI}pR3|eKx?8IfT?B@-L09ii+aKAhiOuRU-h_;9LvDygQ zp@ok+EYiG_4~xaXI&KcHYYl%g{pf6=4ow7qC|4H++8a6&{E3Ae!fqXH|j)SZ|~Hq0<7R|Evs!3#H7TfT(ZZ&a*M?eQe>>$1pVt zust^+Vqe=@le=QUEgd(5RQv~6Y(#YRVw7FRSc^o`B^9H-ALH+&&?N!J-ZL=kodwa5 zp%>iSUql%{;Ws9_Djg{kOF>!cWCXhy@(%S z*RL@x@Qc9#Ct6$A!p+!?4;(&P04(wVnH7tp%x9ZNwK4gc624oYO?1N!)PWH5T^^fw zeV2@sACG=nYgdWKHR+Rwyz%WUSHb~iKuq4y*ZV?LDdBbV4QY;U(@1 zdXL*j3@nE~XvGHKDp6>oy?c+?T9O7Qj^rvDet@mg>PDqn|3bry$j>5h2yRe9@0el# zjyJCoZUosIE}*&?IZpLwW8x>)AHpfdgiRZ&#{Rel<`7djAJ#@NT3z+yu(wz$Vn2&- zIfD-wh67xQUIiHJp$xs)Kso=k{V(*Bp>vu-ZriQh7Tlxq8%!P7p^C}b0%yFNIXd$8 z0ZiBUs1XSmWY9yf>=3+iaUBHYFI+yplxOD-1^GS91hSsIWTU9^!XzrKBvMS8d0LU0 z7eAeTX7$aA$LpiQb=;7}6E7ERzt|#^6G}tu-!esrS1j;w#@-R- zt}F+MF&|3>eRnnH)G%~0q-K(HOaR#|N?XMv(jE(w(|P{7FV7E~${VT1>+eim30`%> ze>e>QKv3}({eIsnu62TqI=>+iRE;y^vFqO`;wVlin&}HA^jUHC{?6iY9YgL9Q&y7q zRSeDusvSu^?-N=33F+H2$guSMx5{bJEbH2_#bcjgZ&afbxPWE#&`_<)zvJOI^@Vre ztx3iNGk)UoA%DmF_-!k|s!#MyE}gf@+$=NgIP=$(vh*0%H|vHD<+Oor(dU9J`hSp# zWNrbXSbUo4NPjn;-!4QLCEM*uU!cgha$vU$vws<=iiQyFDB8f{rwF)7hT+TGrzG3E6v3%=Bo5C=d16pTQvh zw^xN}kP%vmYN$3aE+#J^s?t`&e~+>Ub#Q@r>}M&|D6tO%!s!f1KcF+Ax5w`At>|n? zi!!T}Rek~e#TT10N)xU!_pHLYQ4h`f0|1Vhv{<7{>5J0Hp zpD|OqJ?7{L->zff<`!C@4)6J=e*Nk~8ctV{`KQ6L5MR`Bir!u#LVYmkOFD61f*3;5oCj&oG$8SjTXynE;h zcm7f%n4z_0Lu89AUT>A9CNp3 zKVSxGU&TM^Ric$jdrXvn7TDf+R3E+ORTAwH z*qy+tJ46&~VPITo7?aVdV2Az3T_*5pR;*d04V4f+xy*ILp%wO{oLA zx>dA*@N8e%&=?FMB7cB#Kg1zuf+rtJ)9>h7IG?`Z-jurZWD5m^bgWaiPZNWn`a%#p zM7~>Uv)Cg;Y}{rlVxL1H1Vhxa5c-uv3x1^OhFH}hq@`1nwenr#Bbu&enoVS zb_GoemTMKY0O#`69#5#WtE@E*@)k;qnHBVy6JJv=cq_nhuM=~`(N_2`S}KTveW zz*Q+{3E2sq-e_*yO`?(*LXco8+2nm(x(ZhhP7|4F(gFf+0%6)lhb2I0QC7nbb&XXen3a>{Tfk zK{JX^3Zjd2G-R{p@`j^hb5Z?d*h5@zW_1914A@Y0LC0I3C;pnFR9HgKoK*3@+blaRi)ogZE6Q^TB;=yrj z+ZS#q`P}Ti11xnFQdUh?ZX_+{lkZcp+%ZQw!q3WIg4wJt#>4uFeDbz7RO2$4_xo^t z>#SS%740Pil&mYE2Ct(6ac5E^>Tpo90Qk>Ucp-K4hI`lZie{vN6<iQ z@2n#gRq2dIF$nwr0%1U&za{spexLvV000000000071}5abgY_33SZXEodgx2TseCe z7IEx5JX}EgP*HY58k-C?cM8m>1%U~W@3#9qA#WrrOW^BuU;s^VNvX+nsC z4`Sc)XUYqGM4oOk8;e7)3-&ayz29zK5IY$8OFXEBF z=2S;f_e%elGfTiU&*j9$ZJxWy#k53S=Wrq6sdVdv#R_T z>uhfy3Zt57O&QE=!kltWNu<*>9530CkSCYO!S>k&{sWO^Q_DL|CoaxUUTG~_#gj%% z)~UHR<>k%l+^x`*D>WBwrMYl+0l?iIXT^(fM^Y=pHRM4e!%UH&I-nUg_W9NK7W_U1 z4d&)w`B^d4@5GRI!O}pJJrbQKg(f zy=pu)Yj?=qT3F`kZ^$LB*rz?L zBtuj6X0!7z(UPI2->`c1OE(-}^J<4nrtkLv0e{Q!O-R=;RM>(@Rp!s29Lv@8jqz;O zaAqYh1bKN8)AR2`zW+~_++~St=89iDQ3fz6cDjl>A&+*)SZTD{Ljn@eIgz=Wkerq} z&TT<6_V5%WVb~_it#_w^=S-v|G1OuE2lmfbIercp9|?_p!5$;mNxQbs@jpWriM9QI zl#qUtww+Jki>`vM#8#8p(5F|TKH;G0O^?ZeG@n(qYpMIEI{zqA;p7 zP=1!m4na#Cv=}q?1qqizn7aG~z%=Z?kv)L=d+T07dH^09S!LmRAMbwzGb#s+13PP< zJ!f?4C$!7oPu{HK@pi1&LD=~YPV}b376iq*zLn=8JXf)EJj|cyN~(a3FklIS5oY`N zHG$!V2*iY~?aO4k$G!?uY7(@R|FVd@{q}T4*EBxB?8KyzYfcPt`dk8o8H-J{v6`ObiCO}JPP zj|)>I)}gv2<-Dsb0xT$D6Pu6A!WX}j&?mPAMLm{E<{uJEEtar>Mbx;^`9uJ*1%Rfx ztFIP!&}Ly30)L2kWH5cVhQ#z&^~8)h)M(j^HNF#5u275{t|uwZ%i~r*k;az3Jdor$@u2x>Dx? z+kyFPk$M;(5da-~cl0x9UCUr|^XIc#27`+{TcQf6bt^L^KR=u8C#tmAS!5osX{Qo- z18u7VC}KX9zWE7YVbn*W-fErk<+%<*36kEHVWR9D6FUQgoaHzHnx@i29>m111$*sc zr0m7YE_+mChz}KmcWyE2X8spoHG&-u4fGga~DjWU43w7guAkzwh203p; z0yaJ0$IhL?HRhY`ih;%5@M>m}QU6GPnnxWlh&)=h=VGyfV>Rg3bL1TW)UyY*fU%*)uQL#~CUl zJ3if|?1TSpXO7N|Pt+|KlLJPPPc}lP1ZF`N)y9rZ2FwC{M@4=aX5~Oq!ctqo%p_^> zi@(&b)K&2xdGGVJJQbLJnS(8d`Y^v@`dY$I6(FKrsQCW@NDMf;`^El79t}~N=tb{3nNnbq)JHh%P~YSx^hvH zysRvZM$ol%6|rm%etgtJ=dpaAUvQgD`-#4@Iwg#|D!2P~vjuDB#V5s$tZspd*y3*>!&Znyi-{l{scBv`1ic zO*pJ-4kPUr$;md{I9z5_k2#@VCE^yUcZEAb)m1~>zJSYGt4K7G&5txa?Ynd={sud8 zs4a3S*F))|3o6|Q?k4CuXXgnM58-!*j(c}UF;?RHZK&{m(}#6kWjYwAleMf<)7G6= zWib>L^3vc2 zR3qHyn>w3&18-stkB``CSp7aO5XrIGg`ne(dDMc;XuNkR>k)OWDC0_ZlE)E<4S}Isr!93k| z0p7d0=qglKGGqQ^<VZSwdwdH3H- zcL=3eX82IdP8w7(T48H#ku8OW^k$^T6$}x~r`2F(kD+J#=|rz3##Z5Gc^wnOhTojy zOJzuETNCsc0hQ|lFB`FbL%**G5rY7rtRVpMVl%tQni>eflCRZjQpM1Ptv97P67rpl ztLbI1lm5^k3Mfp?$bK}VdP$}-HP zmW)Li1Q<3nA*>~X5P#3}VxR`xG|q#1yQ}g8p?xlTHcy~~B7fRJP~8wH-O8yl&;aB6 zFieI-zsJl5<&e(Xvp`M?h;ap8oDvi7<}^~U4ckSWG<{uFJQIkBFc1yeH7iE}Tzvkm z4cAOF)+~n4>L$P__X7ou1j_)TX4I(}5#7XR zCttv-75Q{2VRwg)dv{AgoU(zTC~%>Q(bv{_-CC6%50*18g5~rt5D9A*wFzBcdd}w2 zjPMbyXS!R?<2r(4q0O50S?i37LY-%&w+N`p;}h%Rp|Z`2wLtTiGZJm$gT%>$gHoc0 ziBF@qW{do2;G8P#6B4pdOC`WN@XFIP&F--+OklIJ z&==y~Xt;=5(*iJJbMyXgaQOQwUstnrqCtxx{Q@!+SqiwxhTBvh>R1_y74WdXE{Y_4 zVwIPXD$0+jrP0Jpg1bw-890demzX;OMGpub6rzUsfmrX>Y0u;_f>3CUEzG4`{nz#y z+NzDG$%xMHB5K)Q|9r#Ed80;0Tue{?4N4P!0f7pFEVSqodZ!toz(|3?b z9m+oeBD0XJ0}nh3zgg?2#E?lkALBV2C;o2=j=*f+9q-v^UCQ#V0+}^2&Zx4jL0wfD zX+#L8K2PK2?COsm+6YL6C9s8(3EgPpWpd31@xeRo^YLHx<5CFUMam6 zQ147OWWMsq*#l-_cXtclxpW_1y;CQvH*0hTJBzKxq#_~f*1Nhl`#rpwV3ywsa6W#9 zhbiFImayACZmH}P6`DS*1IwXPULTIlPm)CtOaj%{(J2=QhNI=-}dhyOe?67`^x7cM|$Kt4EMYC5)lr?|d>fI8@aT~e2*BV~o14k(F~z!IOuHf=)D ziBEI!Yk+PY)=G{9`YpY|n@@=O;Sgr&P2z_r%)9A`xR9=?lI0Sk#DGU4p)$Iy_-}Ni z_((;Yh?0q$AOf2thDK5BTw<+Z6^`wncx+<_3g008{X}_+Tj7dWeP($u>;I;T6wG5= z_e~7)^wHd@CM7ezo4^N;xusVIh-aobFW!6X`PTuR^7+9&8eYha&BP(PsRYPzO=q;3 zM1zMEM4~%VoHf&CtggY(QCP&wSeDsit%$o)!sZMENa;@8eRR`V5+VURSVHI=H70l4 zWMp--j7I*c#WdXA6hH~S3iqw<-bYPpu{Lre_lpsy5lT-c+ZQy~=w#^Ky?Qt>0%HLM{RqZ+!B!sI&J0VCMfgBwrm zH{bFmacFv?iu4ISCR&Eb%3LURzVz9OxmyasPy-8c|C6DF-)`2~Q))2S$rO~Z({Q

GxWIe=d3giXh<)0dsHizZw9xfuMG1$snNY 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 { if (pre.hasAttribute('data-copy-ready')) return; if (pre.closest('.code-wrapper')) return; // CodeBlock provides its own button + if (pre.classList.contains('mermaid')) return; // Mermaid diagrams are not code blocks pre.setAttribute('data-copy-ready', ''); const btn = document.createElement('button'); diff --git a/src/components/docs/Mermaid.astro b/src/components/docs/Mermaid.astro new file mode 100644 index 00000000..54899a23 --- /dev/null +++ b/src/components/docs/Mermaid.astro @@ -0,0 +1,60 @@ +--- +/** + * Mermaid diagram, rendered client-side from CDN. + * Usage in MDX: B`} /> + * + * The script is `is:inline` so Astro does not bundle it — the CDN module import + * then runs natively in the browser (matching how the rest of this repo loads + * third-party client scripts). The diagram source lives in the page, per the + * docs playbook. In the full monorepo, `pnpm add mermaid` and swap the CDN + * import for `import mermaid from 'mermaid'`. + */ +interface Props { + chart: string; +} +const { chart } = Astro.props; +--- + +

{chart}
+ + + + diff --git a/src/components/docs/Steps.astro b/src/components/docs/Steps.astro index 9fbfbb4a..05dc7810 100644 --- a/src/components/docs/Steps.astro +++ b/src/components/docs/Steps.astro @@ -5,50 +5,10 @@ - + diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts index fa965e76..d250d65a 100644 --- a/src/lib/navigation.ts +++ b/src/lib/navigation.ts @@ -84,6 +84,12 @@ export const tabNavigation: NavTab[] = [ { title: 'Support', href: '/docs/self-hosting/support' }, ] }, + { + title: 'Release notes', + items: [ + { title: "What's new", href: '/docs/release-notes' }, + ] + }, ] }, { @@ -362,21 +368,21 @@ export const tabNavigation: NavTab[] = [ group: 'Observability', icon: 'eye', items: [ - { title: 'Overview', href: '/docs/observe' }, + { title: 'Get Started', href: '/docs/observe' }, + { title: 'Quickstart', href: '/docs/observe/quickstart' }, { title: 'Concepts', items: [ { title: 'Understanding Observability', href: '/docs/tracing/concepts' }, - { title: 'What are Traces?', href: '/docs/tracing/concepts/traces' }, - { title: 'What are Spans?', href: '/docs/tracing/concepts/spans' }, - { title: 'What is OpenTelemetry?', href: '/docs/tracing/concepts/otel' }, - { title: 'What is traceAI?', href: '/docs/tracing/concepts/traceai' }, + { title: 'Spans', href: '/docs/observe/concepts/spans' }, + { title: 'Traces', href: '/docs/observe/concepts/traces' }, + { title: 'OpenTelemetry', href: '/docs/tracing/concepts/otel' }, + { title: 'traceAI', href: '/docs/tracing/concepts/traceai' }, ] }, { title: 'Features', items: [ - { title: 'Set Up Observability', href: '/docs/observe/features/quickstart' }, { title: 'Run Evals on Traces', href: '/docs/observe/features/evals' }, { title: 'Sessions', href: '/docs/observe/features/session' }, { title: 'Users', href: '/docs/observe/features/users' }, diff --git a/src/lib/redirects.ts b/src/lib/redirects.ts index 93b7acbb..2625e00c 100644 --- a/src/lib/redirects.ts +++ b/src/lib/redirects.ts @@ -306,4 +306,5 @@ export const redirectMap: Record = { '/sdk-reference/python-sdk-client': '/docs/sdk', '/sdk-reference/testcase': '/docs/sdk/testcase', '/sdk-reference/tracing': '/docs/sdk/tracing', + '/docs/self-hosting/environment': '/docs/self-hosting/configuration/environment', }; diff --git a/src/pages/docs/observe/concepts/spans.mdx b/src/pages/docs/observe/concepts/spans.mdx new file mode 100644 index 00000000..cfbb4920 --- /dev/null +++ b/src/pages/docs/observe/concepts/spans.mdx @@ -0,0 +1,43 @@ +--- +title: "Spans" +description: "Pinpointing the single step behind a slow or wrong answer." +--- + +## A span is one step + +A span is one operation inside a [trace](/docs/observe/concepts/traces): a single model call, tool call, retrieval, agent step, guardrail check, or evaluator run. It records its own input and output, when it started and finished, whether it succeeded, and, for model calls, the tokens and cost it ran up. Where a trace is the whole request, a span is one step inside it. + +Under the hood, a span is an [OpenTelemetry](/docs/tracing/concepts/otel) span. OpenTelemetry defines the shape, a named, timed unit of work with a status, a parent, and key-value attributes, and traceAI fills those attributes with LLM-specific keys: the span `kind` that says what ran, the prompt and completion, the token counts. So every span you see in Observe is a standard OTel span carrying traceAI's LLM attributes. + + +A parent span, say an agent, holds the child spans it set off, and each of those can have children of its own. That nesting is how Future AGI works out which step triggered which, and it is what lets a trace draw itself as a tree. + + B["chain span"] + A --> C["tool span"] + B --> D["retriever span"] + B --> E["llm span"]`} /> + +Each box is a span with its own timing and attributes. The edges come straight from OpenTelemetry: every span carries the trace ID and its parent span's ID, and OTel propagates that context down your call stack, so a span created deep inside nests under the one above it without you wiring it up. Those same links are what a [trace](/docs/observe/concepts/traces) is rebuilt from. + +## What a span isn't + +- **Not a log line.** A log is a flat text event. A span is a timed unit with structured input, output, status, and attributes, linked to a parent +- **Not an event.** An event is a point-in-time marker inside a span, like an exception. The span is the operation that holds it + +## Why it matters + +A response is only as strong as its weakest step, and that step is usually where things break. The trace tells you a request was slow or wrong; the span tells you which step did it and hands you the evidence: the exact prompt sent to the model, the arguments a tool received, the chunks a retriever pulled back, or the score an evaluator gave. traceAI captures these spans for you on supported frameworks, and where it can't reach, you can [add your own](/docs/observe/features/manual-tracing/create-tool-spans) so no part of your pipeline stays a black box. + +## Keep exploring + + + + The full request that spans are grouped into + + + Add custom spans where auto-instrumentation stops + + diff --git a/src/pages/docs/observe/concepts/traces.mdx b/src/pages/docs/observe/concepts/traces.mdx new file mode 100644 index 00000000..251aa12e --- /dev/null +++ b/src/pages/docs/observe/concepts/traces.mdx @@ -0,0 +1,44 @@ +--- +title: "Traces" +description: "Helping you debug an AI response, step by step." +--- + +## A trace is a tree + +A trace is a tree of [spans](/docs/observe/concepts/spans). The root span is the operation that kicked off the request, and every other span nests under the step that triggered it. They all share one trace ID, so the whole request stitches back together top to bottom, even when steps run across async tasks or services. + + S1["llm.intent_classification"] + T --> S2["tool.check_order_status"] + T --> S3["chain.generate_reply"] + S3 --> S4["retriever.knowledge_base"] + S3 --> S5["llm.response_generation"]`} /> + +The tree above is one support-agent request. The root `support_agent.run` is the whole request. Under it, `llm.intent_classification` reads the question, `tool.check_order_status` looks up the order, and `chain.generate_reply` writes the answer, which itself calls `retriever.knowledge_base` for the refund policy and `llm.response_generation` for the wording. + +Read top to bottom, the tree is the exact path the request took, so when an answer comes out wrong you can see which step caused it. + +## What a trace isn't + +- **Not a session.** A session bundles many traces from one conversation or user. A trace is just one request inside it. See [Sessions and users](/docs/observe/features/session) +- **Not a log line.** Logs are flat text events. A trace is a timed, structured tree with inputs, outputs, and cost at every step + +## Why it matters + +Without traces, a wrong or slow answer is a dead end. You see the output but not the steps behind it, so debugging turns into guesswork over flat logs. A trace turns that into a readable path you can walk: you spot that the retriever pulled the wrong policy chunk, that one tool call dragged on for four seconds, or that an eval flagged the answer as unsupported. Latency, cost, errors, and quality all hang off the same request, so you debug from one place instead of stitching logs together by hand. + +## Keep exploring + + + + The individual operations a trace is built from + + + Group multiple traces into one conversation or customer + + + Instrument your app so it emits traces + + diff --git a/src/pages/docs/observe/index.mdx b/src/pages/docs/observe/index.mdx index 478e3c5f..4dd5a957 100644 --- a/src/pages/docs/observe/index.mdx +++ b/src/pages/docs/observe/index.mdx @@ -1,45 +1,51 @@ --- -title: "Future AGI Observe: Monitor LLM Apps in Production" -description: "Monitor and evaluate LLM applications in production with real-time tracing, session analysis, cost tracking, and alerting." +title: "Get started with Observe" +description: "Observe records every request your AI app makes as a trace you can open, search, and score. Send your first trace, then go deeper" --- -## About +Observe shows you what your AI app actually did in production. Every request becomes a **trace**: the step-by-step record of the model calls, tool calls, and retrievals behind one response. When an answer is wrong, slow, or expensive, you open the trace and read what happened instead of guessing. -Observability is how you monitor your AI application after it goes live. Once your app is in production, things change: user inputs vary, model behavior shifts, and issues come up that testing never caught. Observability gives you a continuous view of how your application is performing so you can stay on top of it. +You only need one trace to begin. Everything else here builds on it. -It tracks every response your application generates, groups them by session and user, scores them for quality, and alerts you when something goes wrong. Instead of finding out about problems from users, you see them in the dashboard first. +Observe trace explorer listing production traces with status, latency, and token columns +*Every production request, captured as a trace and ready to inspect* -Sessions Overview +## Start here ---- - -## How Observability Connects to Other Features - -- **Prototype**: After you promote a winning version in Prototype, its traces continue flowing into Observe so you can monitor production performance against the same quality criteria. [Learn more](/docs/prototype) -- **Evaluation**: Observability uses the same built-in eval templates to score production traces automatically. Any eval you configured in Prototype or Datasets runs the same way here. [Learn more](/docs/evaluation) -- **Alerts**: Observability feeds into the alerting system so you are notified when quality, cost, or latency crosses a threshold in production. [Learn more](/docs/observe/features/alerts) + + + Instrument one call and watch it land in Observe, in about five minutes + + + One line to trace OpenAI, Anthropic, LangChain, and 30+ more + + ---- +## Understand the model -## Getting Started with Observability +A few short pages give you the whole mental model behind Observe. Read these and the rest of the product explains itself: - - Connect the SDK and start capturing traces in minutes. - - - Run evaluations on observed traces and sessions. + + What gets recorded for each request, and how the steps nest - - Group and analyze multi-turn interactions. + + Follow a full conversation, or one customer across sessions - - Track and analyze activity by user. + + The open library that sends your traces to Observe - - Configure alerts for real-time issue detection. + + +## Once your traces are flowing + +Every other feature in Observe is just a different lens on the traces you capture: + + + + Attach quality scores to whole traces or single spans - - Monitor voice agent interactions and call quality. + + Get told the moment a metric slips diff --git a/src/pages/docs/observe/quickstart.mdx b/src/pages/docs/observe/quickstart.mdx new file mode 100644 index 00000000..d3a95900 --- /dev/null +++ b/src/pages/docs/observe/quickstart.mdx @@ -0,0 +1,147 @@ +--- +title: "Quickstart" +description: "Send your first LLM trace to Future AGI Observe in about five minutes" +--- + +Get your first trace into Observe in about five minutes, without changing your app's logic. + +## In this page + +You will install the traceAI instrumentor, register an Observe project, run a single OpenAI call, and confirm the trace in the dashboard with its model, latency, and token cost. The same four steps work for 30+ frameworks, so once OpenAI is traced you have the pattern for the rest of your stack. + +## Prerequisites + +- A Future AGI account and your **`FI_API_KEY`** and **`FI_SECRET_KEY`** (Dashboard → Build → Keys) +- Python 3.11 (or Node 18+ for the TypeScript path) +- An OpenAI API key + + +Pin the packages to the version you test against, so a later release cannot change behavior under you + + +## Steps + + + + Install the core instrumentation package and the OpenAI instrumentor + + + ```bash Python + pip install fi-instrumentation-otel traceAI-openai + ``` + ```bash JS/TS + npm install @traceai/fi-core @traceai/openai + ``` + + + + + Read keys from the environment, never hardcode them in source + + ```bash + export FI_API_KEY="your-futureagi-api-key" + export FI_SECRET_KEY="your-futureagi-secret-key" + export OPENAI_API_KEY="your-openai-api-key" + ``` + + + + `register` returns a tracer provider. Set `project_type` to `OBSERVE`, attach the OpenAI instrumentor, then call OpenAI exactly as you normally would + + + ```python Python + from fi_instrumentation import register, Transport + from fi_instrumentation.fi_types import ProjectType + from traceai_openai import OpenAIInstrumentor + from openai import OpenAI + + # Connect to Future AGI and create (or reuse) an Observe project + trace_provider = register( + project_type=ProjectType.OBSERVE, + project_name="my-first-project", + transport=Transport.GRPC, + ) + + # Auto-instrument OpenAI: every call is now traced + OpenAIInstrumentor().instrument(tracer_provider=trace_provider) + + # Use OpenAI exactly as you normally would + client = OpenAI() + completion = client.chat.completions.create( + model="gpt-4o", + messages=[{"role": "user", "content": "Write a one-sentence bedtime story about a unicorn."}], + ) + print(completion.choices[0].message.content) + ``` + ```typescript JS/TS + import { register, ProjectType } from "@traceai/fi-core"; + import { OpenAIInstrumentation } from "@traceai/openai"; + import { registerInstrumentations } from "@opentelemetry/instrumentation"; + import OpenAI from "openai"; + + // Connect to Future AGI and create (or reuse) an Observe project + const traceProvider = register({ + project_type: ProjectType.OBSERVE, + project_name: "my-first-project", + }); + + // Auto-instrument OpenAI: every call is now traced + registerInstrumentations({ + instrumentations: [new OpenAIInstrumentation({})], + tracerProvider: traceProvider, + }); + + // Use OpenAI exactly as you normally would + const client = new OpenAI(); + const completion = await client.chat.completions.create({ + model: "gpt-4o", + messages: [{ role: "user", content: "Write a one-sentence bedtime story about a unicorn." }], + }); + console.log(completion.choices[0].message.content); + ``` + + + Expected terminal output (the wording varies): + + ```text + Under a sky of silver stars, a gentle unicorn dipped its horn into a + moonlit pool and wished every sleeping child sweet dreams. + ``` + + + + Open **Observe → my-first-project → Tracing**. Within a few seconds you will see one trace row with **status OK**, the **model**, the **latency**, and the **token count**. Click it to read the prompt, the completion, and the span timing + + Observe trace explorer with one new OpenAI trace showing OK status, model, latency, and token columns + *Your request, now a trace. If the row is here with an OK status, instrumentation is working end to end* + + + +## What you just captured + +That row is a [trace](/docs/observe/concepts/traces), the full record of one request. Because this example made a single OpenAI call, the trace holds one [span](/docs/observe/concepts/spans): the `llm` operation, carrying the model, the prompt and completion, the token counts, and the cost. + +The same four steps instrument 30+ frameworks. Swap the instrumentor for your stack and the flow is identical, see [all framework integrations](/docs/tracing/auto). + +## Not seeing your trace? + +- **No trace appears**: a short script can exit before the exporter flushes. Call `trace_provider.force_flush()` before the process ends +- **Wrong or empty project**: confirm `project_name` matches the project you are viewing, and that `FI_API_KEY` and `FI_SECRET_KEY` belong to this workspace +- **Still nothing**: widen the date picker (it defaults to the last 7 days) and turn on **Auto refresh** + +## Dive deeper + + + + The mental model the rest of Observe is built on + + + One step inside a trace: a model call, a tool call, a retrieval + + + Attach quality scores to your production traces + + + Get told the moment a metric slips + + diff --git a/src/pages/docs/tracing/concepts/index.mdx b/src/pages/docs/tracing/concepts/index.mdx index 59d88314..7250aed2 100644 --- a/src/pages/docs/tracing/concepts/index.mdx +++ b/src/pages/docs/tracing/concepts/index.mdx @@ -45,10 +45,10 @@ Each **trace** is one request or execution. Each **span** is one operation (LLM, ## Next Steps - + The top-level unit: one request = one trace. - + The building blocks inside every trace. diff --git a/src/plugins/vite-docs-transform.mjs b/src/plugins/vite-docs-transform.mjs index dab3550b..2dffacfc 100644 --- a/src/plugins/vite-docs-transform.mjs +++ b/src/plugins/vite-docs-transform.mjs @@ -22,6 +22,7 @@ const COMPONENT_MAP = { CopyButton: '@docs/CopyButton.astro', Expandable: '@docs/Expandable.astro', Icon: '@docs/Icon.astro', + Mermaid: '@docs/Mermaid.astro', Note: '@docs/Note.astro', ParamField: '@docs/ParamField.astro', Prerequisites: '@docs/Prerequisites.astro', diff --git a/src/styles/global.css b/src/styles/global.css index fa266fda..1872c939 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -565,3 +565,70 @@ kbd { stroke-dasharray: 4 4; fill: none; } + +/* Steps component: number badges + connector line (the "step chain"). + Lives here, not in Steps.astro, so it is loaded on every page. The custom + FastNav swaps body content but not page-specific