For anyone who needs to know where credentials go and what the extension never reads, follows or logs. Back to the README.
-
Credentials go only where you pointed them. Like Praxis's own OpenCode plugin, which attaches credentials only when the base URL equals
PRAXIS_BASE_URL, credentials fromINFERENCE_GATEWAY_*variables attach only to the provider whose base URL equalsINFERENCE_GATEWAY_BASE_URL. The comparison normalises scheme, host, port and path, and ignores a trailing slash or/v1. A config-file provider that names one of those variables for another URL is refused, and nothing is sent to it:$ cat $PI_CODING_AGENT_DIR/inference-gateway.json { "providers": { "other": { "baseUrl": "http://127.0.0.1:47812", "apiKeyEnv": "INFERENCE_GATEWAY_API_KEY" } } } $ pi --list-models | grep -E "^(provider|gateway|other) " [pi-inference-gateway] other: refused — it uses INFERENCE_GATEWAY_API_KEY, which only authenticate to INFERENCE_GATEWAY_BASE_URL (http://127.0.0.1:47811), but its baseUrl is http://127.0.0.1:47812. Use a variable of your own (apiKeyEnv/passwordEnv) for this gateway. provider model context max-out thinking images gateway claude-sonnet-5 1M 128K yes yes gateway gemini-3.5-flash 1.0M 65.5K yes yes
Give any other gateway a variable of its own (
apiKeyEnv,passwordEnv). An overlay that changes a provider's URL keeps theapiKeyEnv,passwordEnvandusernameEnvit inherits from the shared file, so if the new gateway needs a different credential, set its own variable in the overlay. -
Only your user-level config is read:
~/.pi/agent/inference-gateway.jsonand its local overlayinference-gateway.local.json, or the same files under$PI_CODING_AGENT_DIR, merged over the same two files in the extension's own install directory (see Shipping a config with the extension). WhenINFERENCE_GATEWAY_CONFIG_FILEis set, only the file it names is read, none of those (see One exact config file). The host that starts pi sets it in the process environment. A project's.pi/directory is still never consulted, so a cloned repository cannot point your credentials at its own host. An agent that can already change pi's process environment can already change everyINFERENCE_GATEWAY_*variable, so this variable adds no new way in. Its purpose is to let a host point pi at a file the agent cannot write, which closes the gap between the host's check of the file and pi's read of it. That holds only while the host ensures three things, none of which the extension checks: neither the file's directory nor any directory above it is writable by the agent (otherwise the agent can replace the file, or a directory containing it, by renaming another over it); where the file or a directory on its path is a symlink, the same holds for the path it resolves to, through every link: the resolved file and every directory above it are not writable by the agent; and every child pi inherits the sameINFERENCE_GATEWAY_CONFIG_FILEvalue, and for a~/path the same home directory, since an agent that can start pi with an environment of its own can point it at another file. A provider whosebaseUrlEnvresolves to another URL thanINFERENCE_GATEWAY_BASE_URLis refusedINFERENCE_GATEWAY_*credentials exactly like a literalbaseUrl. -
No secrets in the file. Keys and passwords are referenced by variable name or file path; a literal
apiKeyorpassword, or anauthorization/x-api-keyentry inheaders, is refused. No!commandkeys, no shell-out. -
Redirects are never followed, on model requests or on discovery: a redirect is an error, so a key cannot be forwarded to another origin.
-
Credentials are never logged. Warnings name variables and files, never their values. A discovery error shows the start of a
text/plainerror body (or of a UTF-8 body sent without a content-type) only after replacing the credentials it sent: the token, the Basic username, password,user:passwordpair and its base64, and the auth header value, each in its literal, JSON-escaped and percent-encoded form. If any credential is shorter than 8 characters (Basic's default usernamegatewayis 7), the body is replaced by(body omitted). A body that has control characters other than tab, line feed and carriage return (as UTF-16 text has) is not shown at all, so a credential in such an encoding is dropped rather than shown. Other encodings of a credential are not recognised. -
Model-request error bodies are printed by pi, not by this extension, and are not redacted: a gateway or backend that echoes the request's credentials in an error can expose them there.