From 7461fc83aafb91fb0ab7e6dc7a0a7adf4e0da138 Mon Sep 17 00:00:00 2001 From: Scott Werner Date: Wed, 28 Oct 2026 10:40:22 -0400 Subject: [PATCH] docs: clarify server and direct model credential sources --- docs/internal/server-secrets-strategy.md | 44 ++++++++++++------- .../administration/server-configuration.mdx | 2 +- .../public/administration/troubleshooting.mdx | 2 +- docs/public/api-reference/fabro-api.yaml | 20 +++++---- docs/public/core-concepts/models.mdx | 32 +++++++++++++- docs/public/getting-started/quick-start.mdx | 18 +++----- docs/public/integrations/bedrock.mdx | 6 +-- docs/public/integrations/litellm.mdx | 6 ++- docs/public/integrations/modal.mdx | 4 +- docs/public/reference/cli.mdx | 4 +- docs/public/reference/sdk.mdx | 4 +- .../fabro-api-client/src/models/model.ts | 2 +- .../fabro-api-client/src/models/provider.ts | 2 +- 13 files changed, 94 insertions(+), 52 deletions(-) diff --git a/docs/internal/server-secrets-strategy.md b/docs/internal/server-secrets-strategy.md index 3f492ea46..457584202 100644 --- a/docs/internal/server-secrets-strategy.md +++ b/docs/internal/server-secrets-strategy.md @@ -43,22 +43,36 @@ the vault: `FABRO_JWT_PRIVATE_KEY` and `FABRO_JWT_PUBLIC_KEY` are removed. `SESSION_SECRET` is the single auth root. -Provisioning into the vault is not the same as the resolver being vault-only. `VaultCredentialSource` -(`lib/foundation/fabro-auth/src/vault_source.rs`) reads each secret name lithos-llm asks for from -the process environment first and the vault second, under the same conventional names. Which paths -that environment lookup is live on is a per-process question: +For conventional provider API-key names, `VaultCredentialSource::new` and +`SqlVaultCredentialSource::new` check the process environment before the vault. Their +`vault_only` constructors disable that lookup. OAuth records and interpolated secret headers +resolve through the vault separately. The owning process chooses the source: -- **Server process** — inert. `lib/apps/fabro-server/src/server.rs:2453` builds - `SqlVaultCredentialSource::vault_only(...)`, so the env lookup always returns `None`. -- **Worker process** — wired but effectively inert for provider keys. `build_llm_source` - (`lib/components/fabro-workflow/src/pipeline/initialize.rs:275`) builds the run's credential - source with `VaultCredentialSource::new`, which carries the process-env fallback; the - provider-listing path does the same via `with_env_lookup(process_env_var)` - (`operations/start.rs:529`). But the worker's env was cleared and repopulated from - `WORKER_ENV_ALLOWLIST` (`lib/apps/fabro-server/src/spawn_env.rs:6`), which does not include - provider API keys. Exporting a provider key in the server's shell therefore has no effect on runs. -- **`fabro exec` and direct `fabro-llm` SDK usage** — live. These have no vault and read process - env deliberately. +- **Server process** — `lib/apps/fabro-server/src/server.rs` constructs + `SqlVaultCredentialSource::vault_only(...)`. Model calls, provider listing and gateway + completions therefore do not use process-environment provider API keys. +- **Worker process** — `runtime_spec` in + `lib/apps/fabro-cli/src/commands/run/petri_worker.rs` constructs `VaultCredentialSource::new`. + The worker environment is cleared and repopulated from `WORKER_ENV_ALLOWLIST` in + `lib/apps/fabro-server/src/spawn_env.rs`, which excludes conventional provider API keys, + including Bedrock bearer tokens. Exporting them in the server's shell has no effect on runs. +- **Direct `fabro exec` (no server target)** — `CommandContext::llm_source` in + `lib/apps/fabro-cli/src/command_context.rs` opens the local SQL secret store and constructs + `SqlVaultCredentialSource::new`. Conventional API keys use environment-first lookup, + then that local store. +- **`fabro exec --server ...`** — `FABRO_SERVER` also selects this mode. The CLI sends completions through the gateway; the target + server resolves credentials using its vault-only source. +- **Direct SDK usage** — the caller selects a `CredentialProvider`. For example, + `VaultCredentialSource::environment_only()` explicitly reads process-environment keys. + +Bedrock SigV4 is a separate mechanism: the AWS default credential chain's identity inputs +are deliberately allowlisted into workers so sessions can refresh. This does not enable +environment lookup for Bedrock bearer tokens. Providers with no authentication need no key. + +Installation can accept an explicit stdin or named-environment credential input and persist +it in the vault; this is provisioning, not a runtime fallback. Endpoint catalog overrides such +as `OPENAI_BASE_URL` are also independent of credential lookup. The public contract lives in +`docs/public/core-concepts/models.mdx` under **Credential sources**. ## Which process resolves what diff --git a/docs/public/administration/server-configuration.mdx b/docs/public/administration/server-configuration.mdx index 215f279c9..3cb7716a5 100644 --- a/docs/public/administration/server-configuration.mdx +++ b/docs/public/administration/server-configuration.mdx @@ -391,7 +391,7 @@ fabro secret set OPENAI_API_KEY sk-... fabro secret set GEMINI_API_KEY AI... ``` -`fabro exec` and direct library usage can opt into env-backed credential sources explicitly. Runs cannot: the Fabro server reads provider keys from the vault after the temporary startup migration, and workers start from a cleared environment that does not inherit provider keys. +Exporting a conventional provider API key in the server's shell neither configures the provider nor overrides a vault value. Workers start from a cleared environment that does not inherit those keys. `fabro exec --server ...` also uses the target server's credentials. Direct `fabro exec` (no server target) checks the invoking process environment before its local secret store for conventional API-key names; SDK callers choose their credential source. Bedrock SigV4 uses the separate AWS default credential chain. See [Credential sources](/core-concepts/models#credential-sources) for the full distinction. | Variable | Provider | |---|---| diff --git a/docs/public/administration/troubleshooting.mdx b/docs/public/administration/troubleshooting.mdx index d3a59f056..dc980c2ef 100644 --- a/docs/public/administration/troubleshooting.mdx +++ b/docs/public/administration/troubleshooting.mdx @@ -28,7 +28,7 @@ LLM provider probe failures are reported as errors. Use `--verbose` to see the u **Server exited after I finished the install wizard** — Expected. The server writes `~/.fabro/settings.toml` and exits cleanly at the end of the wizard. Start it again with `fabro server start` to boot in configured mode, or run it under a supervisor with a restart policy (for example docker-compose `restart: unless-stopped`, systemd, or Railway's restart-on-exit) so the second start happens automatically. -**"No API key configured"** — For runs, set at least one provider key in the server vault with `fabro provider login` or `fabro secret set`; workers start from a cleared environment, so exporting a provider key in the server's shell has no effect on runs. `fabro exec` and direct library usage can use env-backed credential sources explicitly. Run `fabro doctor` to verify server connectivity. +**"No API key configured"** — For runs, set at least one provider key in the server vault with `fabro provider login` or `fabro secret set`; workers start from a cleared environment, so exporting a provider key in the server's shell has no effect on runs. Direct `fabro exec` (no server target) can read keys from the invoking shell or local secret store; `fabro exec --server ...` uses the target server's vault. SDK callers choose their credential source. See [Credential sources](/core-concepts/models#credential-sources). Run `fabro doctor` to verify server connectivity. **Stall watchdog timeouts** — If runs are cancelled unexpectedly, the agent may be stuck or the LLM provider may be slow. Check `FABRO_LOG=debug` output for `Agent.LlmRetry` events. Increase `stall_timeout` in the graph if needed, or add [fallback providers](/core-concepts/models) to handle outages. diff --git a/docs/public/api-reference/fabro-api.yaml b/docs/public/api-reference/fabro-api.yaml index a734c4ddc..985ab7793 100644 --- a/docs/public/api-reference/fabro-api.yaml +++ b/docs/public/api-reference/fabro-api.yaml @@ -8693,11 +8693,11 @@ components: expected_secret_name: type: ["string", "null"] description: | - Suggested vault secret name for configuring this provider, - derived from the first vault credential reference in the - provider catalog. Null when the provider has no vault - credential (e.g. no-auth or env-only providers). Used to - prefill the create-secret form. + Suggested vault secret name for configuring this provider: the + first conventional secret name for its catalog authentication scheme. + Null when that scheme declares no conventional secret names (for + example, no-auth providers). Used to prefill the create-secret form; + providers such as Modal require more than one secret. ProviderId: description: LLM provider identifier. @@ -8868,10 +8868,12 @@ components: configured: type: boolean description: | - Whether credential material is present for this model's provider on the - server (vault entry or environment variable). Does NOT imply the - credential is valid or that requests will succeed; call - `POST /models/{id}/test` to verify usability. + Whether the server resolved credentials and built a client for this + model's provider. Provider API keys and OAuth records come from the + server vault, not process environment variables. Bedrock SigV4 uses + the separate AWS default credential chain; no-auth providers need no + key. Does NOT imply authentication or model requests will succeed; + call `POST /models/{id}/test` to test usability. ModelTestResult: description: Result of testing a model in `basic` or `deep` mode. diff --git a/docs/public/core-concepts/models.mdx b/docs/public/core-concepts/models.mdx index 149294276..49d175eb4 100644 --- a/docs/public/core-concepts/models.mdx +++ b/docs/public/core-concepts/models.mdx @@ -72,7 +72,7 @@ Fabro performs this selection once when creating a run and persists the chosen p | `qwen3.8-max` | venice | `qwen`, `qwen-max`, `qwen3.8`, `qwen-3.8`, `qwen38`, `qwen-3.8-max`, `qwen38-max` | 1M | $2.50 / $7.50 | n/a | | `qwen3.8-27b` | venice | `qwen-27b`, `qwen-3.8-27b`, `qwen38-27b` | 262K | $0.45 / $3.20 | n/a | -Each provider requires its own API key. Server-backed workflows read provider credentials from the server vault (for example `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `DEEPSEEK_API_KEY`, or `POOLSIDE_API_KEY` set with `fabro secret set` or `fabro provider login`). Standalone SDK/CLI flows can opt into env-backed credential sources explicitly. See the [Quick Start](/getting-started/quick-start) for setup. +Providers can use API keys, OAuth, AWS credentials, or no authentication, depending on their configuration. See [Credential sources](#credential-sources) below and the [Quick Start](/getting-started/quick-start#configure-api-keys) for setup. Claude Fable 5 is available as an explicit model but is not the default Anthropic model. If Fable refuses a request, Fabro reports the refusal as a content-filter LLM error and applies the configured `run.model.fallbacks` chain when one is present. @@ -135,7 +135,7 @@ A `provider/model` selector such as `openai/gpt-5.6-sol` pins the provider and n Model roles are separate: the provider's `default_model` controls normal model selection for workflow execution, while `small_default = true` on a model row marks the provider's small utility model for metadata tasks such as generated run titles. If a provider has no small default, Fabro falls back to that provider's default model. -Provider auth has two parts. The lithos `auth` scheme says how a credential is sent: `{ type = "bearer" }`, `{ type = "header", name = "x-api-key" }`, `{ type = "headers" }` for providers that take several secret headers, `{ type = "none" }`, or `{ type = "aws" }`. lithos also says which secret names a provider reads: `OPENAI_API_KEY` for `openai`, `GEMINI_API_KEY` then `GOOGLE_API_KEY` for `gemini`, `MODAL_TOKEN_ID` and `MODAL_TOKEN_SECRET` for `modal`, and `_API_KEY` for a provider you define. Fabro looks each name up in the process environment first and the server vault second. Custom headers for any provider go in `default_headers` as literal text or `{{ secrets.NAME }}` tokens; put credentials in secrets and reference them with `{{ secrets.NAME }}` instead of a bare literal. +Provider auth has two parts. The lithos `auth` scheme says how a credential is sent: `{ type = "bearer" }`, `{ type = "header", name = "x-api-key" }`, `{ type = "headers" }` for providers that take several secret headers, `{ type = "none" }`, or `{ type = "aws" }`. lithos also says which secret names a provider reads: `OPENAI_API_KEY` for `openai`, `GEMINI_API_KEY` then `GOOGLE_API_KEY` for `gemini`, `MODAL_TOKEN_ID` and `MODAL_TOKEN_SECRET` for `modal`, and `_API_KEY` for a provider you define. The source of those values depends on how the model call is made; see [Credential sources](#credential-sources). Custom headers for any provider go in `default_headers` as literal text or `{{ secrets.NAME }}` tokens. Secret tokens resolve against the vault, not process environment variables; put credentials in secrets and reference them instead of using a bare literal. Workflow runs add `x-session-id: ` to native HTTP model requests, including model-based hooks, run titles, Ask Fabro and pull request descriptions. The ID stays the same across retries, provider fallback and resume; separate runs get separate IDs. Explicit provider `default_headers` take precedence regardless of header-name casing. Calls outside a run do not receive an automatic session header. @@ -151,6 +151,34 @@ Costs come from the lithos `pricing` table on each model row. Each token bucket Provider fields in configuration, APIs, and model routing are provider ID strings. Built-in names like `anthropic`, `openai`, and `gemini` still work, but custom IDs like `proxy` work anywhere a provider ID is accepted. +## Credential sources + +`fabro exec` is direct when neither `--server` nor `FABRO_SERVER` selects a server. With either target selector, it sends model calls through that server. + +For `fabro run`, server model calls, and `fabro exec --server ...`, store provider API keys and OAuth credentials in the **target server's vault**. This also applies when the server runs locally on your laptop. Exporting a provider API key in either the CLI's shell or the server's shell does not configure or override that server's model credentials. + +```bash +fabro secret set OPENAI_API_KEY sk-... +# For a remote server, target the same server used for model calls: +fabro secret --server https://fabro.example.com set OPENAI_API_KEY sk-... +``` + +Use `fabro provider login` for supported API-key and OAuth login flows. The provider's secret names are the vault entry names, not instructions to export environment variables. For providers that require an API-key secret, an environment-only key leaves the server provider unconfigured; with conflicting environment and vault values, the server uses the vault value. Workers do not inherit conventional provider API keys from the server's environment. + +| Model-call context | Credential source | +| --- | --- | +| Workflows and server model calls, including `fabro exec --server ...` | Target server's vault for provider API keys and OAuth records. | +| Direct `fabro exec` (no server target) | For conventional API-key names, the invoking process environment first, then the local Fabro secret store. Stored OAuth records are resolved separately. | +| Direct SDK use | The caller chooses the credential source. `VaultCredentialSource::environment_only()` explicitly reads conventional keys from the process environment; `vault_only(...)` disables that lookup. | + +Installation can accept a key explicitly from stdin or a named environment variable and save it to the vault. That is a provisioning step, not a server credential fallback. Startup does not import provider keys from process environment variables, `.env`, or `server.env`. + +Endpoint settings are separate from credentials. For example, `OPENAI_BASE_URL` can change the normal server's OpenAI endpoint without making `OPENAI_API_KEY` an environment-backed server credential. + +[Bedrock SigV4](/integrations/bedrock#configure-credentials) is a separate authentication mechanism: it uses the AWS default credential chain, whose identity inputs are deliberately available to workers. Bedrock bearer API keys still follow the vault rule above. Providers configured with `auth = { type = "none" }` do not need an API key. External ACP agents manage their own model authentication; this section describes Fabro's model client. + +## Provider integrations + ### Venice Fabro ships a built-in [Venice](/integrations/venice) provider with a curated catalog of Venice-hosted Kimi, Grok, GLM, DeepSeek, and Qwen models. Store its API key with `fabro provider login --provider venice`. Pin `provider = "venice"` when a shared model slug must use Venice instead of a higher-priority direct provider. diff --git a/docs/public/getting-started/quick-start.mdx b/docs/public/getting-started/quick-start.mdx index b9a9ecdb2..d6b15d610 100644 --- a/docs/public/getting-started/quick-start.mdx +++ b/docs/public/getting-started/quick-start.mdx @@ -65,22 +65,16 @@ This creates `.fabro/project.toml` and a starter workflow under `.fabro/workflow ## Configure API keys -For local CLI runs, export at least one LLM provider key in your shell: - -```bash -ANTHROPIC_API_KEY=sk-ant-... -OPENAI_API_KEY=sk-... -GEMINI_API_KEY=AI... -``` - - -You only need one provider key to get started. Add more to enable multi-model workflows. - -For server-backed runs, store provider keys in the server vault instead: +`fabro run` uses the Fabro server even when you run it from a local terminal. If installation has not already configured a provider, store a key in that server's vault: ```bash fabro secret set ANTHROPIC_API_KEY sk-ant-... ``` + +You can also use `fabro provider login --provider anthropic` for guided setup. You only need one provider to get started; add more to enable multi-model workflows. + + +Exporting a provider key in your shell does not configure server-backed workflows. For a remote server, use `fabro secret --server https://fabro.example.com set ANTHROPIC_API_KEY sk-ant-...` and `fabro run --server https://fabro.example.com hello` so both commands use the same server. Direct `fabro exec` and SDK callers have different [credential sources](/core-concepts/models#credential-sources). ## Run your first workflow diff --git a/docs/public/integrations/bedrock.mdx b/docs/public/integrations/bedrock.mdx index 78b5a6737..69cd48cdb 100644 --- a/docs/public/integrations/bedrock.mdx +++ b/docs/public/integrations/bedrock.mdx @@ -45,11 +45,11 @@ fabro secret set AWS_BEARER_TOKEN_BEDROCK bedrock-api-key-... fabro secret set BEDROCK_API_KEY bedrock-api-key-... ``` -Runs read the bearer token from the vault only. Workers start from a cleared environment and the bearer token is not on the inherited allowlist, so exporting it in the server's shell has no effect on runs. `fabro exec` and direct `fabro-llm` SDK usage do read it from process env. +Runs read the bearer token from the vault only. Workers start from a cleared environment and the bearer token is not on the inherited allowlist, so exporting it in the server's shell has no effect on runs. Direct `fabro exec` (no server target) checks process environment before the local secret store for these names; SDK callers can explicitly choose an environment-backed source. `fabro exec --server ...` uses the target server's vault. **AWS SigV4** (IAM-scoped): with no API key configured, Fabro signs each request using the AWS default credential chain — environment keys, shared profile, EC2/ECS instance roles, IRSA/web identity, SSO. Expiring session credentials refresh automatically. -The order is fixed by lithos-llm: `AWS_BEARER_TOKEN_BEDROCK`, then `BEDROCK_API_KEY`, then the AWS default chain. Each name is read from the process environment first and the server vault (`fabro secret set`) second — so on a server, prefer `secret set`. To select a non-default AWS profile for SigV4, set `AWS_PROFILE` (it, and the rest of the AWS credential-chain variables, are passed through to workflow workers). +The order is fixed by lithos-llm: `AWS_BEARER_TOKEN_BEDROCK`, then `BEDROCK_API_KEY`, then the AWS default chain. For server model calls and workflows, those two bearer-token names are read from the vault only. The AWS default chain is separate from bearer-token lookup; it can use environment credentials and other AWS identity sources. To select a non-default AWS profile for SigV4, set `AWS_PROFILE` (it, and the rest of the AWS credential-chain variables, are passed through to workflow workers). **Bearer-vs-SigV4 precedence.** Because the bearer key is tried before SigV4, setting `AWS_BEARER_TOKEN_BEDROCK` makes the `bedrock` (Converse) provider authenticate with that key too — not just the `bedrock-openai` mantle provider below. If your key is valid only for mantle (it lacks `bedrock:InvokeModel*` on the runtime), every Converse model then fails with *"Authentication failed."* Use a key that covers both surfaces, or keep Converse on SigV4 by leaving both Bedrock secret names unset and enabling only `bedrock`. @@ -124,7 +124,7 @@ Bedrock-specific request fields pass through verbatim via `provider_options.bedr ## Troubleshooting -**"no AWS credentials provider found"** — Neither an API key nor any AWS chain source resolved. Set `AWS_BEARER_TOKEN_BEDROCK` (or `BEDROCK_API_KEY`), or configure standard AWS credentials. +**"no AWS credentials provider found"** — Neither an API key nor any AWS chain source resolved. Store `AWS_BEARER_TOKEN_BEDROCK` (or `BEDROCK_API_KEY`) with `fabro secret set` on the target server, or configure the AWS default credential chain. For direct execution, follow the [credential-source rules](/core-concepts/models#credential-sources). **`AccessDeniedException` / 403** — The IAM principal lacks `bedrock:InvokeModel*` for the model, or model access has not been granted in the Bedrock console for your Region (Claude needs the per-Region use-case approval; third-party models need `aws-marketplace:Subscribe`). diff --git a/docs/public/integrations/litellm.mdx b/docs/public/integrations/litellm.mdx index 3ca268d32..20c69c15f 100644 --- a/docs/public/integrations/litellm.mdx +++ b/docs/public/integrations/litellm.mdx @@ -44,12 +44,14 @@ For a server-owned secret: fabro secret set LITELLM_API_KEY sk-proxy-key ``` -`fabro exec` and direct `fabro-llm` SDK usage can use an env-backed credential source explicitly: +For direct `fabro exec` (no server target), export the key in the invoking shell. SDK callers can explicitly choose an environment-backed credential source: ```bash export LITELLM_API_KEY=sk-proxy-key ``` +`fabro exec --server ...` uses the target Fabro server's vault, even when the CLI has a key in its own environment. See [Credential sources](/core-concepts/models#credential-sources). + If your local LiteLLM proxy does not enforce authentication, use a placeholder value such as `anything`; the OpenAI-compatible client still needs a credential value. ## Use LiteLLM models @@ -97,7 +99,7 @@ The provider's `default_model` names its default. You may also mark one small ut ## Troubleshooting -**"No API key configured"** — For runs, set `vault:LITELLM_API_KEY` with `fabro secret set LITELLM_API_KEY ...`. Exporting it in the server's shell has no effect on runs: workers start from a cleared environment and provider keys are not inherited. For `fabro exec` or direct SDK usage, export `LITELLM_API_KEY` in the invoking shell and use an env-backed credential source. +**"No API key configured"** — For runs, store `LITELLM_API_KEY` in the target server vault with `fabro secret set LITELLM_API_KEY ...`. Exporting it in the server's shell has no effect on runs: workers start from a cleared environment and provider keys are not inherited. For direct `fabro exec` (no server target), export `LITELLM_API_KEY` in the invoking shell or store it in the local secret store. SDK callers must choose the appropriate credential source. **Connection refused** — Confirm the LiteLLM proxy is running and that `base_url` is reachable from the Fabro process. For Docker deployments, `localhost` means the Fabro container unless you point it at a host or service name. diff --git a/docs/public/integrations/modal.mdx b/docs/public/integrations/modal.mdx index 749cba7a6..381ded20f 100644 --- a/docs/public/integrations/modal.mdx +++ b/docs/public/integrations/modal.mdx @@ -113,9 +113,9 @@ digraph Example { ## Direct SDK environment credentials -The built-in Modal provider authenticates with two headers, `Modal-Key` and `Modal-Secret`, read from the secrets `MODAL_TOKEN_ID` and `MODAL_TOKEN_SECRET`. Direct SDK use reads the same two names from the process environment. +The built-in Modal provider authenticates with two headers, `Modal-Key` and `Modal-Secret`, read from the secrets `MODAL_TOKEN_ID` and `MODAL_TOKEN_SECRET`. For environment-backed SDK use, export both names and select `VaultCredentialSource::environment_only()` explicitly. Alternatively, use `VaultCredentialSource::vault_only(...)` with a vault holding both tokens. -For direct SDK use, enable Modal and set its endpoint URL in the `[llm]` overlay, then build the client with `fabro_llm::build_client` over a `VaultCredentialSource` whose vault holds both secrets. The catalog you pass to the client must be built from the same settings file with `fabro_llm::build_catalog`. +Enable Modal and set its endpoint URL in the `[llm]` overlay, then build the client with `fabro_llm::build_client` over your chosen credential source. The catalog you pass to the client must be built from the same settings file with `fabro_llm::build_catalog`. ```toml title="settings.toml" [llm.providers.modal] diff --git a/docs/public/reference/cli.mdx b/docs/public/reference/cli.mdx index 6cf2ebea1..82dcd65b3 100644 --- a/docs/public/reference/cli.mdx +++ b/docs/public/reference/cli.mdx @@ -17,7 +17,7 @@ These flags apply to all subcommands: | `-h, --help` | Print help | | `-V, --version` | Print version | -Connection-target flags like `--storage-dir` and `--server` are command-specific, not global. Fabro no longer auto-loads `~/.fabro/.env`; persist server-owned credentials with `fabro provider login` / `fabro secret set`, or provide environment variables in the invoking shell. +Connection-target flags like `--storage-dir` and `--server` are command-specific, not global. Fabro no longer auto-loads `~/.fabro/.env`. Configure server model credentials with `fabro provider login` or `fabro secret set` on the target server; shell provider keys do not configure `fabro run` or `fabro exec --server ...`. Direct `fabro exec` (no server target) checks the invoking process environment before the local secret store for conventional API-key names. See [Credential sources](/core-concepts/models#credential-sources), including the separate Bedrock SigV4 mechanism. ## Configuration @@ -46,7 +46,7 @@ url = "https://fabro.example.com/api/v1" `[cli.exec]` config applies to `fabro exec`. `[run.model]` sets the default workflow model/provider for commands like `fabro run` and `fabro preflight`. `[cli.target]` stores connection info for commands that can target a remote Fabro server. -`fabro model` uses `[cli.target]` by default when no explicit `--storage-dir` is passed. `fabro exec` remains a local session unless you pass `--server`, even if `[cli.target]` is configured. +`fabro model` uses `[cli.target]` by default when no explicit `--storage-dir` is passed. `fabro exec` remains a direct session unless you select a server with `--server` or `FABRO_SERVER`, even if `[cli.target]` is configured. Explicit `http(s)://...` targets are always treated as remote servers. They do not inherit identity from a local daemon, a local storage dir, or `~/.fabro/dev-token`. For remote URLs, use `fabro auth login --server ...` or a stored CLI auth session. diff --git a/docs/public/reference/sdk.mdx b/docs/public/reference/sdk.mdx index 5307736f4..7e72acb7b 100644 --- a/docs/public/reference/sdk.mdx +++ b/docs/public/reference/sdk.mdx @@ -331,7 +331,9 @@ The `fabro_llm::catalog` module reads Fabro policy from the catalog: `enabled_pr `ClientOptions::standard()` turns on the lithos retry middleware (three attempts with short exponential backoff) and local attachment inlining. Add middleware with `with_middleware`, replace a provider's adapter with `with_adapter`, or set `http` to inject a configured HTTP client. `fabro_llm::build_offline_client(catalog, options)` builds a client whose only providers are custom adapters, which is how `fabro exec --server` routes every call through a Fabro server. -Credential sources live in `fabro-auth`: `VaultCredentialSource` reads a Fabro vault with an optional process-environment fallback (`VaultCredentialSource::environment_only()` for SDK callers with no vault), and `SqlVaultCredentialSource` reads the server's secret store. lithos-llm decides which secret names a provider reads (`OPENAI_API_KEY`, `MODAL_TOKEN_ID` and `MODAL_TOKEN_SECRET`, or `_API_KEY` for an operator-defined provider); Fabro's vault is keyed by those same names. +Credential sources live in `fabro-auth`. For conventional API-key names, `VaultCredentialSource::new(...)` and `SqlVaultCredentialSource::new(...)` check process environment first, then their in-memory vault or SQL secret store. Use `VaultCredentialSource::environment_only()` when the SDK should read only process environment keys, or either source's `vault_only(...)` constructor to disable environment lookup. Stored OAuth records and `{{ secrets.NAME }}` header tokens resolve through the vault separately. + +The Fabro server uses `SqlVaultCredentialSource::vault_only(...)`; an SDK's choice of source does not change server behavior. lithos-llm decides which secret names a provider reads (`OPENAI_API_KEY`, `MODAL_TOKEN_ID` and `MODAL_TOKEN_SECRET`, or `_API_KEY` for an operator-defined provider); Fabro's vault is keyed by those same names. Bedrock SigV4 retains its separate AWS default credential chain. See [Credential sources](/core-concepts/models#credential-sources). #### Requests and responses diff --git a/lib/packages/fabro-api-client/src/models/model.ts b/lib/packages/fabro-api-client/src/models/model.ts index 0de1f0971..251e403b4 100644 --- a/lib/packages/fabro-api-client/src/models/model.ts +++ b/lib/packages/fabro-api-client/src/models/model.ts @@ -75,7 +75,7 @@ export interface Model { */ 'small_default': boolean; /** - * Whether credential material is present for this model\'s provider on the server (vault entry or environment variable). Does NOT imply the credential is valid or that requests will succeed; call `POST /models/{id}/test` to verify usability. + * Whether the server resolved credentials and built a client for this model\'s provider. Provider API keys and OAuth records come from the server vault, not process environment variables. Bedrock SigV4 uses the separate AWS default credential chain; no-auth providers need no key. Does NOT imply authentication or model requests will succeed; call `POST /models/{id}/test` to test usability. */ 'configured': boolean; } diff --git a/lib/packages/fabro-api-client/src/models/provider.ts b/lib/packages/fabro-api-client/src/models/provider.ts index aec171ca9..ec9ab14b1 100644 --- a/lib/packages/fabro-api-client/src/models/provider.ts +++ b/lib/packages/fabro-api-client/src/models/provider.ts @@ -59,7 +59,7 @@ export interface Provider { */ 'configured': boolean; /** - * Suggested vault secret name for configuring this provider, derived from the first vault credential reference in the provider catalog. Null when the provider has no vault credential (e.g. no-auth or env-only providers). Used to prefill the create-secret form. + * Suggested vault secret name for configuring this provider: the first conventional secret name for its catalog authentication scheme. Null when that scheme declares no conventional secret names (for example, no-auth providers). Used to prefill the create-secret form; providers such as Modal require more than one secret. */ 'expected_secret_name'?: string | null; }