Credentials & logins¶
In short
- Each agent CLI signs in on the server, as the account that runs the backend: a
subscription login made once (
codex login,claudethen/login,gemini) or an API key in the backend's environment. - Settings → Agents and the Agent menu show where each agent's credential comes from, never the key itself.
- Secrets for other connections live encrypted in the vault,
config/vault.json; a connection refers to one asvault://<name>. Back the vault up with.secret_key. - Every step attempt gets a fresh ParleML token for the person who started the session, revoked when the attempt ends. Nothing to configure.
A cloud-backed session needs two kinds of credential: the CLI's login, which decides whose subscription or API account pays for the model, and the connections' credentials, which let the agent reach MCP servers. ParleML stores neither in a session.
Local inference without a cloud login¶
For Ollama and LM Studio, configure the provider, server URL and model in the profile editor. The workspace picker and preflight check the local server and installed model instead of the CLI's cloud login. The CLI must still be installed. See Local models with Ollama or LM Studio for setup, supported agents and guidance for CPU-only laptops. Connection credentials below still apply.
The CLI's login¶
Each CLI runs as the backend's operating-system user, with that user's own login or an API key from the backend's environment.
| CLI | Sign in on the server | Or set (backend environment) | How preflight checks |
|---|---|---|---|
| Claude Code | run claude, then /login (subscription) |
ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN |
claude auth status |
| Codex | codex login, with ChatGPT to use your plan |
OPENAI_API_KEY, CODEX_API_KEY, CODEX_ACCESS_TOKEN |
a key is set, else codex login status |
| Gemini CLI | run gemini, choose Sign in with Google |
GEMINI_API_KEY, GOOGLE_API_KEY; or Vertex AI: GOOGLE_GENAI_USE_VERTEXAI=true with GOOGLE_CLOUD_PROJECT and Application Default Credentials |
a key is set; else, for Vertex AI, the project and a credentials file (GOOGLE_APPLICATION_CREDENTIALS or gcloud's default); else a saved sign-in in ~/.gemini/oauth_creds.json (or under GEMINI_CLI_HOME) |
| Cursor | — | CURSOR_API_KEY or PARLEML_AGENTS_CURSOR_API_KEY (Cursor Dashboard → Integrations) |
the key is set |
- A CLI process gets an allow-listed environment: system basics (
PATH,HOME, locale, temp), its own credential variables above, and proxy settings. Nothing else from the backend's environment reaches it. - Codex ignores the user's own
config.toml(--ignore-user-config) and Gemini CLI loads only the granted MCP servers, so a person's personal MCP servers on that machine do not leak into a session. Their login still applies. A profile may include the person's own settings instead, where the installation allows it (Host-native rules & hooks). - CLI keys are read from the process environment, not from the vault.
For a saved Codex login, run codex login and then codex login status
as the account that starts the backend. If CODEX_HOME is set, use the same
value for login and for the backend; the adapter forwards it to Codex.
A successful CLI login establishes the credential, not a successful ParleML
session: run the profile's preflight and verify an actual session separately.
Which sign-in a session uses¶
The same check preflight runs says, for each CLI, where its credential comes
from: signed in (claude.ai), OPENAI_API_KEY is set, signed in with
Google (…), or why it is not signed in. Never the key itself. It is shown
- in the Agent menu and Home's Work with an agent, next to each agent
the workspace's profile lets a person pick (
GET /api/agent/agents?scope_id=…); an agent that is not signed in cannot be picked; - on Settings → Agents, in the Signed in with column (the admin agent
catalog's
loginper adapter).
A CLI that does not answer within PARLEML_AGENTS_PREFLIGHT_TIMEOUT_SECONDS
reads as not signed in.
Preflight runs these checks for every CLI a profile uses (its own and
any skill_agents pin) before each session starts, and on Run preflight.
A failed check refuses the start with 503 and names the check. A login that
expires mid-session fails the attempt with login_required; the banner
names the fix (for example "run codex login on this machine") and Retry
continues once it is done.
Connection credentials¶
<data_root>/config/connections.yaml holds references, never values:
knowledge-hub:
kind: mcp
mcp_name: knowledge
transport: http
url: https://kb.example.com/mcp
auth:
type: bearer # or header, with header: X-Api-Key
secret: vault://knowledge-hub
A vault://<name> reference names an entry in the vault,
<data_root>/config/vault.json: every secret the installation stores,
Fernet-encrypted with the data-root key (<data_root>/.secret_key). Settings
→ Connections writes the entry when someone types the secret (as
vault://<connection id>); ParleML also stores installation secrets there,
such as its identifier-pseudonymisation key. No API returns the secret values.
- The value is read at the moment it is needed (a session start or resume, preflight, Test), fresh each time, so a new secret needs no restart and never blocks a resume.
- It is never written to
run.json, returned by the admin API, or put on a command line (how it reaches the CLI). - A reference with no value fails preflight ("has no value in the vault") instead of sending an empty header.
- Back up
vault.jsontogether with.secret_key; one without the other cannot be read.
How a secret reaches the CLI¶
Details: environment variables, not arguments
CLIs get the secret in their environment under a generated PARLEML_MCP_* name, and their
MCP configuration names the variable: Claude Code's per-attempt --mcp-config file
(${PARLEML_MCP_…}, in the run's directory, never the work directory), Codex's
env_http_headers, Gemini CLI's settings file. Codex's shell policy hides the variables
from the agent. A Claude Code session granted Bash can read them.
ParleML's own MCP: minted tokens¶
The parleml connection uses auth: {type: minted, provider: parleml}.
Instead of a stored secret, every attempt gets a fresh ParleML API token:
- for the person who started the session, so an agent can never do more than they can;
- scoped by the skill's
parleml-scope:analyst(default),computeorbuilder, a builder token bound to the session's workspace; - named "agent session … · step … · attempt n", so the token list shows where it came from;
- expiring at the attempt's wall-clock cap and revoked when the attempt ends;
- recorded in
provenance/<token_id>.jsonbefore the agent gets it.
A ParleML token is minted only for ParleML's own /mcp. The connection
URL must have the same origin and path as <origin of
PARLEML_AGENTS_SESSION_MCP_URL>/mcp. Pointed anywhere else, the provider
refuses to mint; preflight reports "will not mint for connection …" and
sessions do not start. The backend logs a warning at boot when the parleml
connection does not point at this server. Fix the URL in Settings →
Connections. The parleml connection is built in: it cannot be deleted, and
the backend writes it again when it is missing.
Tokens for your own agent¶
Agents you run yourself (Claude Desktop, Cursor, Codex, …) connect with a
token from Settings → Access (administrators mint them)
or through OAuth; see Tokens & scopes. These tokens
are separate from session tokens, and what they create reports kind:
token in provenance. API tokens never drive sessions: the session routes
accept signed-in people only.
Next¶
- Local models: run an agent with no cloud login.
- Tokens & scopes: tokens for the agents you run yourself.