From d9fbccf2e2f4e3db940728c85ea11f3165f35974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Lange?= Date: Thu, 12 Mar 2026 23:50:15 +0100 Subject: [PATCH] docs(onboarding): add client integration quickstarts --- CHANGELOG.md | 1 + README.md | 4 ++- docs/INTEGRATIONS.md | 24 ++++++++++++++++ docs/ONBOARDING.md | 28 +++++++++++++++++++ foundrygate/onboarding.py | 58 +++++++++++++++++++++++++++++++++++++++ tests/test_onboarding.py | 48 ++++++++++++++++++++++++++++++++ 6 files changed, 162 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e103f45..150f345 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is intentionally lightweight and human-readable. Group entries by rel - Added `foundrygate-onboarding-report` plus a testable onboarding report module for many-provider and many-client readiness checks - Added `foundrygate-onboarding-validate` so onboarding blockers can fail fast in local setup and CI-style validation flows +- Added built-in OpenClaw, n8n, and CLI quickstart examples to the onboarding report and integration docs so client onboarding can stay copy/paste friendly ## v0.7.0 - 2026-03-12 diff --git a/README.md b/README.md index 43b36f6..9c2df65 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,8 @@ $EDITOR .env ./scripts/foundrygate-onboarding-report ``` +The onboarding report now includes concrete OpenClaw, n8n, and CLI quickstart hints so you can move from a generic health check to a client-specific integration path without leaving the terminal. + If you prefer the Linux service path instead of a manual Python run, jump to [Helper Scripts](#helper-scripts) and use `./scripts/foundrygate-install`. If you install the project as a package, the `foundrygate` and `foundrygate-stats` console scripts are available. @@ -837,7 +839,7 @@ Running `./scripts/foundrygate-install` also creates symlinks in `/usr/local/bin | --- | --- | | `foundrygate-bootstrap` | Creates `.env` from `.env.example` if needed, creates a local state dir, and appends a safe local `FOUNDRYGATE_DB_PATH` if none is set | | `foundrygate-doctor` | Checks for config/env presence, writable DB path, at least one configured provider key, and optional local health endpoints | -| `foundrygate-onboarding-report` | Summarizes provider readiness, client-profile coverage, routing layers, and onboarding suggestions for many-provider and many-client setups | +| `foundrygate-onboarding-report` | Summarizes provider readiness, client-profile coverage, routing layers, onboarding suggestions, and concrete OpenClaw/n8n/CLI quickstarts | | `foundrygate-onboarding-validate` | Exits non-zero when onboarding blockers exist and prints warnings for common multi-provider and multi-client misconfigurations | | `foundrygate-install` | Installs the unit file, creates `/var/lib/foundrygate`, creates helper symlinks, reloads `systemd`, and starts the service | | `foundrygate-start` | Runs `systemctl start foundrygate.service` | diff --git a/docs/INTEGRATIONS.md b/docs/INTEGRATIONS.md index 4cb75c3..1c57c06 100644 --- a/docs/INTEGRATIONS.md +++ b/docs/INTEGRATIONS.md @@ -22,6 +22,15 @@ Use: - [openclaw-integration.jsonc](../openclaw-integration.jsonc) - `client_profiles.presets: ["openclaw"]` for a standard starting point +Minimal direction: + +```json +{ + "baseUrl": "http://127.0.0.1:8090/v1", + "primary": "foundrygate/auto" +} +``` + ## n8n n8n can use FoundryGate as a stable local model gateway. @@ -39,6 +48,14 @@ This gives you: - shared fallback behavior - route debugging through `POST /api/route` +Minimal direction: + +```text +Base URL: http://127.0.0.1:8090/v1 +Model: auto +Header: X-FoundryGate-Client: n8n +``` + ## CLI clients CLI tools should also use the same local gateway where possible. @@ -60,6 +77,13 @@ Recommended pattern: - `X-FoundryGate-Locality` - `X-FoundryGate-Profile` +Minimal direction: + +```bash +export OPENAI_BASE_URL=http://127.0.0.1:8090/v1 +export OPENAI_API_KEY=local +``` + ## Provider onboarding When onboarding a new provider: diff --git a/docs/ONBOARDING.md b/docs/ONBOARDING.md index 9191f02..13882e2 100644 --- a/docs/ONBOARDING.md +++ b/docs/ONBOARDING.md @@ -26,6 +26,8 @@ $EDITOR .env ./scripts/foundrygate-onboarding-report ``` +`foundrygate-onboarding-report` now includes concrete OpenClaw, n8n, and CLI quickstart hints. Use it after every provider or client change to keep the deployment understandable for the next operator as well. + ### 1. Add one provider - define the provider in `config.yaml` @@ -80,6 +82,32 @@ Start with: Then tighten it only if the default is not good enough. +### 3a. Start from one of the built-in quickstarts + +OpenClaw: + +```json +{ + "baseUrl": "http://127.0.0.1:8090/v1", + "primary": "foundrygate/auto" +} +``` + +n8n: + +```text +Base URL: http://127.0.0.1:8090/v1 +Model: auto +Header: X-FoundryGate-Client: n8n +``` + +CLI: + +```bash +export OPENAI_BASE_URL=http://127.0.0.1:8090/v1 +export OPENAI_API_KEY=local +``` + ### 4. Add request hooks only if needed Keep hooks opt-in and narrow. Good uses are: diff --git a/foundrygate/onboarding.py b/foundrygate/onboarding.py index 8612d74..f27ffd3 100644 --- a/foundrygate/onboarding.py +++ b/foundrygate/onboarding.py @@ -111,6 +111,53 @@ def build_onboarding_report( if update_check.get("enabled") and not auto_update.get("enabled"): suggestions.append("Keep auto_update disabled until the provider and client set is stable.") + enabled_presets = set(client_profiles.get("presets", [])) + profile_names = set(client_profiles.get("profiles", {}).keys()) + integration_examples = { + "openclaw": { + "recommended": "openclaw" in enabled_presets or "openclaw" in profile_names, + "header": "x-openclaw-source: planner", + "profile": "openclaw", + "snippet": [ + '"baseUrl": "http://127.0.0.1:8090/v1"', + '"primary": "foundrygate/auto"', + ], + "notes": [ + "Keep one-agent and many-agent traffic on the same OpenAI-compatible base URL.", + "Use x-openclaw-source when you want sub-agent traffic to resolve differently.", + ], + }, + "n8n": { + "recommended": "n8n" in enabled_presets or "n8n" in profile_names, + "header": "X-FoundryGate-Client: n8n", + "profile": "n8n", + "snippet": [ + "Base URL: http://127.0.0.1:8090/v1", + "Model: auto", + ], + "notes": [ + "Start workflow traffic with the n8n preset before adding custom policy rules.", + "Use route dry-runs to confirm cheaper or local-first defaults before" + " production runs.", + ], + }, + "cli": { + "recommended": "cli" in enabled_presets or "cli" in profile_names, + "header": "X-FoundryGate-Client: codex", + "profile": "cli", + "snippet": [ + "export OPENAI_BASE_URL=http://127.0.0.1:8090/v1", + "export OPENAI_API_KEY=local", + ], + "notes": [ + "Use a stable client tag such as codex, claude, or kilocode to keep" + " traces readable.", + "Only add hook-based locality or provider overrides when one CLI flow" + " truly needs them.", + ], + }, + } + return { "config_path": str(Path(config_path) if config_path else Path.cwd() / "config.yaml"), "env_file": str(resolved_env), @@ -146,6 +193,7 @@ def build_onboarding_report( "auto_update_enabled": bool(auto_update.get("enabled")), "rollout_ring": auto_update.get("rollout_ring", "early"), }, + "integrations": integration_examples, "suggestions": suggestions, } @@ -196,6 +244,7 @@ def render_onboarding_report(report: dict[str, Any]) -> str: client_block = report["clients"] routing_block = report["routing"] ops_block = report["operations"] + integration_block = report["integrations"] preset_text = ", ".join(client_block["presets"]) if client_block["presets"] else "none" fallback_text = ( ", ".join(routing_block["fallback_chain"]) if routing_block["fallback_chain"] else "none" @@ -251,6 +300,15 @@ def render_onboarding_report(report: dict[str, Any]) -> str: ] ) + lines.extend(["", "Integration quickstarts"]) + for client_name, data in integration_block.items(): + readiness = "ready" if data["recommended"] else "needs preset or custom profile" + lines.append(f"- {client_name}: {readiness}") + lines.append(f" header: {data['header']}") + lines.append(f" profile: {data['profile']}") + for snippet_line in data["snippet"]: + lines.append(f" example: {snippet_line}") + if report["suggestions"]: lines.extend(["", "Suggestions"]) lines.extend(f"- {item}" for item in report["suggestions"]) diff --git a/tests/test_onboarding.py b/tests/test_onboarding.py index 950b1a5..8532f29 100644 --- a/tests/test_onboarding.py +++ b/tests/test_onboarding.py @@ -54,6 +54,8 @@ def test_onboarding_report_marks_missing_api_keys_and_presets(tmp_path: Path): assert report["providers"]["ready"] == 0 assert report["providers"]["missing_api_keys"] == ["deepseek-chat"] assert report["clients"]["presets"] == ["openclaw"] + assert report["integrations"]["openclaw"]["recommended"] is True + assert report["integrations"]["n8n"]["recommended"] is False assert ( "Keep auto_update disabled until the provider and client set is stable." in report["suggestions"] @@ -105,6 +107,8 @@ def test_onboarding_report_marks_local_worker_ready(tmp_path: Path): assert report["providers"]["ready"] == 1 assert report["providers"]["local_workers"] == 1 assert "local-worker: local-worker / openai-compat / local / ready" in text + assert "Integration quickstarts" in text + assert "header: X-FoundryGate-Client: codex" in text def test_onboarding_validation_blocks_missing_env_and_unready_providers( @@ -204,3 +208,47 @@ def test_onboarding_validation_passes_for_ready_multi_provider_setup(tmp_path: P assert validation["ok"] is True assert validation["blockers"] == [] + + +def test_onboarding_report_marks_all_builtin_integrations_ready(tmp_path: Path): + env_file = tmp_path / ".env" + env_file.write_text("DEEPSEEK_API_KEY=sk-demo\n", encoding="utf-8") + + config_file = tmp_path / "config.yaml" + config_file.write_text( + """ +fallback_chain: + - deepseek-chat +providers: + deepseek-chat: + backend: openai-compat + base_url: "https://api.deepseek.com/v1" + api_key: "${DEEPSEEK_API_KEY}" + model: "deepseek-chat" + tier: default +client_profiles: + enabled: true + default: generic + presets: ["openclaw", "n8n", "cli"] + profiles: + generic: {} + rules: [] +routing_policies: + enabled: false + rules: [] +request_hooks: + enabled: false + hooks: [] +update_check: + enabled: true +auto_update: + enabled: false +""".strip(), + encoding="utf-8", + ) + + report = build_onboarding_report(config_path=config_file, env_file=env_file) + + assert report["integrations"]["openclaw"]["recommended"] is True + assert report["integrations"]["n8n"]["recommended"] is True + assert report["integrations"]["cli"]["recommended"] is True