Credentials & Subscriptions
Credential files & declarations, the vault, encryption, OAuth, subscription headroom and failover, PATs. Short, grounded answers with links to the full documentation.
35 questions
- •How do credentials work inside a Trinity agent?
- •How do I add or edit credentials on an agent?
- •Can I change credentials on a running agent without restarting it?
- •What is the .credentials.enc file, and is it safe to commit to git?
- •Do I need to re-enter credentials every time an agent restarts?
- •What kinds of credential files can I inject into an agent?
- •Why does Trinity reject some files when I try to inject them?
- •Can I inject binary credentials like certificates or keystores?
- •Can I connect an agent to Google, Slack, GitHub, or Notion without pasting API keys?
- •Can I add my Claude key without SSH-ing to the server?
- •What happens to my agents when I connect the first Claude credential or remove the platform API key?
- •Can I check a subscription token before registering it?
- •Why was my Gemini key refused, and which agents get it?
- •What are subscription credentials?
- •Do I have to assign a subscription to every new agent manually?
- •What happens when my agent hits a rate limit on its Claude subscription?
- •What happens when every subscription is rate-limited?
- •How do I see how much of a subscription's limit is already used?
- •Why does a subscription show more than 100% of its limit?
- •Does reading subscription headroom cost me quota?
- •Can Trinity warn me before a subscription hits its weekly limit?
- •How does Trinity know a rate-limited subscription has recovered?
- •If I rotate a subscription token, will it interrupt agents mid-task?
- •Why is the Register Subscription button disabled in Settings?
- •Should I use a per-agent GitHub PAT or the platform-wide one?
- •Can I use my own GitHub token instead of the platform-wide one?
- •Do I need a GitHub token to build an agent from a public repo?
- •Are my credentials ever stored in Trinity's database?
- •I upgraded Trinity — do I need to rotate my platform API keys?
- •What is the Credential Vault, and how does an agent use it?
- •How do I rotate the platform encryption key?
- •How do I move an agent's credentials to another Trinity instance?
- •How do I know which credentials an agent actually needs?
- •How does a template declare the credentials it needs?
- •I rotated the platform GitHub token — do I need to restart my agents?
How do credentials work inside a Trinity agent?
Every agent keeps its credentials as files in its own container, following a simple pattern: .env is the source of truth (plain KEY=VALUE pairs), .mcp.json.template declares which credentials the agent needs using ${VAR} placeholders, and .mcp.json is generated at runtime from the template plus .env. Trinity writes these files directly into the agent — credentials are injected, not passed around as loose environment variables. The Credentials tab reads the template to show you each required credential as configured or missing. See Credential Management.
How do I add or edit credentials on an agent?
Open the agent's detail page and click the Credentialstab. You'll see the credentials the agent requires, each marked configured (green) or missing (red). Add values one of four ways: the Setup checklist (per-variable inputs with descriptions and setup links), Quick Inject (paste .env-style KEY=VALUE pairs, merged into the agent's .env), Upload Credential File(one file to a destination path — a service-account JSON, a TLS key, a kubeconfig), or Import from Git (decrypt the .credentials.enc backup in the agent's workspace; Export to Git writes it). There is no separate name/value entry form. See Credential Management.
Can I change credentials on a running agent without restarting it?
Yes — credential updates hot-reload. When you paste or edit credentials on a running agent, Trinity updates the .env file and regenerates .mcp.json immediately; no restart is needed. See Credential Management.
What is the .credentials.enc file, and is it safe to commit to git?
.credentials.encis an encrypted backup of an agent's credentials, produced by the export function and encrypted with AES-256-GCM using the platform's encryption key. Because only the ciphertext is stored, the file is safe to keep in the agent's git repository. Export captures the full injected credential set — every allow-listed credential file present in the agent, text and binary alike — not just .env and .mcp.json. Import decrypts the archive and re-validates every path against the same injection policy on the way in. See Credential Management.
Do I need to re-enter credentials every time an agent restarts?
No. Credential files live in the agent's home directory, which sits on a persistent volume that survives restarts and container recreation. One thing that does not happen automatically: a fresh agent created from a repository that has a .credentials.enc committed but no .envis not filled in on startup — the startup script still tries, but the internal route it called no longer exists, so the attempt is logged as "Could not auto-import credentials" and the agent starts without them. Use Import from Git on the Credentials tab (or the import endpoint) once, and the credentials persist from then on. See Credential Management.
What kinds of credential files can I inject into an agent?
Injection accepts a curated allowlist of credential file types, not just .env. Allowed: the core files (.env, .credentials.enc, .mcp.json— the last is also content-validated), Google Cloud SDK credentials under .config/gcloud/, a Kubernetes .kube/config, TLS certificate and key material (*.pem, *.key, *.crt, *.cert, *.p12, *.pfx), and SSH key pairs (.ssh/id_* only). Anything outside the allowlist is rejected. See Credential Management.
Why does Trinity reject some files when I try to inject them?
A deny-list takes precedence over the allowlist, and it blocks anything that gets executed or sourced when the agent starts: shell startup files (.bashrc, .profile, .zshrc, and friends), agent instruction files (CLAUDE.md, AGENTS.md, anything under .claude/), .mcp.json.template, .ssh/authorized_keys and .ssh/config, anything under .git/ or bin/, plus absolute paths and ..traversal. This is deliberate — it keeps credential injection from becoming a way to run arbitrary code in the container. If a legitimate credential file is rejected, place it at one of the allowed paths instead. See Credential Management.
Can I inject binary credentials like certificates or keystores?
Yes. Binary credential files — certificates, keystores, service-account bundles — round-trip as base64 via the files_b64 field on the inject endpoint, and the encrypted export format carries binary and text files alike. So a .p12 keystore or a PEM bundle survives export, backup, and import intact. See Credential Management.
Can I connect an agent to Google, Slack, GitHub, or Notion without pasting API keys?
Not today. Trinity ships a small OAuth helper API for those four providers that reports which ones are configured (from client IDs and secrets set as backend environment variables) and builds the provider's authorization URL, but it does not complete the exchange: there is no callback handler and no OAuth button on the Credentials tab, so approving access at the provider never turns into a stored token. Obtain the provider token yourself and add it to the agent as a KEY=VALUE credential; the agent's .mcp.json.template picks it up through ${VAR} placeholders. The one complete OAuth flow is the platform-level Slack workspace install (Install to Workspace under Slack Integration settings), which is separate from per-agent credentials. See OAuth Credentials.
Can I add my Claude key without SSH-ing to the server?
Yes — no terminal and no .envedit is needed for any platform key. On a new install the first-run setup's Connect Claude step takes either a Claude subscription token (from claude setup-token, prefix sk-ant-oat01-) or an Anthropic API key (sk-ant-api…), and pasting one into the other's tab is caught before anything is sent. Later, or on an install that skipped it, use Settings → Integrations → API Keys: Check & save tests the key with its provider before it is stored, and Remove deletes it (the .env value, if any, applies again). A key saved in Settings wins over the same key in .env and takes effect without a restart. To get back to a skipped setup step, use Settings → General → First-run setup → Re-run setup. See Platform Keys.
What happens to my agents when I connect the first Claude credential or remove the platform API key?
Both trigger the same adoption sweep. Connecting the first credential — the API key, or a subscription registered on an install with no platform key — assigns it to every Claude-runtime agent that has no credential and is not opted out of platform credentials, such as the starter fleet a fresh install comes with; agents that were deliberately set up with their own key, or have already completed a run, are left alone. Removeon the API key runs it in reverse: agents that were running on that key move onto a registered subscription, which is the usual order when migrating off a metered key — register the subscription, then delete the key. Running agents are restarted in the background one at a time; an agent in the middle of a task is skipped and picks the credential up on its next start. Each adoption is recorded in the audit log, and the save response reports connected_agents. See Platform Keys and Subscription Credentials.
Can I check a subscription token before registering it?
Yes. The first-run Connect Claude step checks the token with Anthropic before it registers anything, and the same check is available over the API as POST /api/subscriptions/test with {token} — one minimal request on the plan, nothing stored — returning valid, a status such as ok, rate_limited or invalid_token, and the fix to apply. The Add Subscription form under Settings → Integrations → Claude Subscriptions only checks the sk-ant-oat01- prefix; a bad token registered there shows up later as an auth failure event on the subscription. See Subscription Credentials.
Why was my Gemini key refused, and which agents get it?
A Gemini key must start with AIza— a key without that prefix is refused at Check & save. Once saved (Settings → Integrations → API Keys, or the Other keys step of first-run setup) it powers voice conversations, Telegram voice-note transcription and generated agent avatars; voice switches on without a restart, and avatars are generated with Generate Default Avatars under Settings → Generalor from an agent's avatar menu. An agent created on the Gemini runtime receives the key as GEMINI_API_KEY. GEMINI_API_KEY (or GOOGLE_API_KEY) in the server's .env remains the fallback when nothing is saved in Settings. See Platform Keys.
What are subscription credentials?
A subscription credential is a Claude Max or Pro token (from claude setup-token, prefix sk-ant-oat01-) registered once with Trinity so that several agents can share it. Register it under Settings → Integrations → Claude Subscriptions with a name and type; Trinity stores it AES-256-GCM encrypted and injects it into assigned agents as an environment variable. The table shows each subscription's agent count and a Pressure cell, and expanding a row shows its assigned agents with assign and unassign controls plus live usage. Registering a name that already exists replaces its token and hot-reloads every running agent on it. See Subscription Credentials.
Do I have to assign a subscription to every new agent manually?
No — every new agent (system agents excepted) is auto-assigned. Trinity skips any subscription that failed in the last 2 hours, then picks the one with the most cached headroom: furthest from whichever of its 5-hour or 7-day limits is nearer. Only when no usable headroom reading exists does it fall back to fewest-agents-first with an alphabetical tie-break. You can reassign at any time by expanding the row under Settings → Integrations → Claude Subscriptions or from the auth badge dropdown in the agent's header; only the agent's owner or an admin can change an assignment. See Subscription Credentials.
What happens when my agent hits a rate limit on its Claude subscription?
With auto-switch on (the default), the turn is not lost. If the subscription is already known to be refusing before the turn starts — a fresh provider reading says so, or it hit a limit in the last 2 hours with nothing fresher to the contrary — Trinity switches the agent before dispatching, so the first message after a limit does not burn a failed attempt. If the provider refuses mid-turn, Trinity records the failure event, switches the agent, hot-reloads the new token into the running container (no recreate, so in-flight work keeps running), and re-issues the turn once on the new subscription, with the rest of the agent's execution timeout — so a long turn is not cut short. The destination is chosen by cached headroom: candidates that failed in the last 2 hours are skipped unless they have provably recovered, and the survivors are ranked furthest from the nearer 5h/7d wall in 10-point bands, with fewest agents as the tie-break. Every switch is logged as an activity on the agent and raises a high-priority notification saying what failed and why the destination was chosen. The toggle lives under Settings → Integrations → Claude Subscriptions; auto-switch still depends on the refusal surfacing as a rate-limit or auth-class error. See Subscription Credentials.
What happens when every subscription is rate-limited?
With Fall back to the platform API keyon (the default) and a platform Anthropic API key configured, Trinity clears the agent's subscription assignment and restarts it on the API key so the turn completes, with a Switched to the platform API keynotification. This is a permanent reassignment, not a temporary redirect — reassign a subscription deliberately when you want spend back on it. With the fallback off, or with no platform key configured (the toggle warns when there isn't one), the turn fails and the error names the earliest known reset time. See Subscription Credentials.
How do I see how much of a subscription's limit is already used?
The Pressure column under Settings → Integrations → Claude Subscriptions gives the one-glance state: 5h: 42% · 7d: 88% when a provider reading under 30 minutes old exists, rate-limited in red, an amber event count when there were failures but no fresh reading, ok, or an em dash when usage couldn't be read. Expand the row for the Usage block: live headroom per window with its reset time, whether the figure is actual (Anthropic) from a provider probe or observed(Trinity's own estimate from recorded consumption), observed tokens, cost and messages for the last 5h and 7d, the 24h failure events split into rate-limit and auth, and a Refresh button that probes now (re-clicking within 60 seconds serves the cached reading). Show per-agent breakdown lists which agents burn the quota so you can see who to move or stagger. Admins see the same figures on the Dashboard as the Subscription pressure Grid tile and the per-agent sub limit / sub 429s / sub auth chips on tiles and List rows. See Subscription Credentials and Dashboard.
Why does a subscription show more than 100% of its limit?
Because it is past its limit. A plan that can keep running beyond its cap reports its usage as a share of that cap, so a reading such as 7d: 120% is correct, not a display error. Trinity counts that subscription as past its limit: it ranks it behind subscriptions with room left when auto-assigning or switching, and the weekly-limit alert fires for it. Earlier releases could show such a reading as about 1%; an old reading corrects itself on the next probe, but history recorded before the fix keeps its old figure. See Subscription Credentials.
Does reading subscription headroom cost me quota?
A little. The 5h/7d percentages come from a provider probe that spends roughly a dozen tokens of the subscription's own quota (visible in the Anthropic console). The Check subscription quota automatically toggle (on by default) governs every probe Trinity runs on its own: the ambient refresh while a dashboard or the Settings page is open (at most one probe per 15 minutes per subscription), the 5-minute re-check of a subscription still marked rate-limited, and the hourly sample behind the weekly-limit alert. Turn it off and headroom only updates when you click Refresh— the recovery re-check and the weekly alerts stop too. Every probe is kept as a history row for 30 days, so utilization trends are answerable over the API (GET /api/subscriptions/{id}/headroom/history); viewing history never probes, and no page charts it yet. See Subscription Credentials.
Can Trinity warn me before a subscription hits its weekly limit?
Yes. Warn me before the weekly limit (under Settings → Integrations → Claude Subscriptions) raises an operator-queue alert when a subscription passes a set share of its 7-day window — default 75, allowed range 50–99, or 0 to turn it off. Trinity samples each subscription about once an hour and files one alert per subscription per weekly window into Operations → Needs Response; the urgency follows your burn rate (low if you're on track to finish the window under 100%, high if you'll run out before the reset), and a second, escalating alert fires at 90% or at your threshold if that is higher. When every registered subscription is past the threshold, a single fleet-wide high alert replaces the per-subscription ones. The status line under the control says whether the alert is actually running or why it isn't — no subscriptions registered, threshold set to 0, or automatic quota checks off. See Subscription Credentials.
How does Trinity know a rate-limited subscription has recovered?
The rate-limited badge clears as soon as a provider probe says the subscription is being served again; while automatic quota checks are on, Trinity re-probes any subscription still wearing the badge every 5 minutes, so it never has to wait out the 2-hour failure window. While the subscription is limited, its row says when the limit returns. Two things are deliberately never shown as a rate limit: a rejected token is recorded as an authevent — the fix is to re-register the token — and the provider's own "approaching the limit" warning tier counts as pressure (the near chip on the Dashboard), not as a limit. Past auth events alone do not trigger a pre-dispatch switch, since a credential problem may be shared by every subscription; a turn the provider actually rejects still switches and retries. See Subscription Credentials.
If I rotate a subscription token, will it interrupt agents mid-task?
No. Re-registering a subscription with a fresh token pushes the new token to every running agent on that subscription via hot-reload, and reassigning an agent to a different subscription swaps the token in place the same way. Turns already in flight finish on the old token; the next turn picks up the new one. Container recreation is only needed for image, template, or auth-mode changes (such as switching between subscription and API key), and on older agent base images that lack the hot-reload endpoint the switch falls back to a recreate. See Subscription Credentials.
Should I use a per-agent GitHub PAT or the platform-wide one?
Trinity stores one platform-wide GitHub PAT (Settings → Integrations → API Keys, or the Other keysstep of first-run setup) that every agent inherits by default — its reach is whatever the token's owner can reach on GitHub. Set a per-agent PAT override when an agent needs to push to a repository the platform token can't see, or when you want to limit blast radius by giving each agent its own narrowly-scoped token. Per-agent PATs are validated when you set them and stored encrypted; clearing the override reverts the agent to the platform PAT. When the platform PAT changes, Trinity propagates the new token to every running agent within seconds — agents with their own override are skipped. See GitHub PAT Setup.
Can I use my own GitHub token instead of the platform-wide one?
Yes. Store a personal access token under Settings → MCP Keys → Personal GitHub Token (a tab every user can open), and Trinity uses it when you create agents — so you're not confined to the admin's platform-wide token and its repo scope. At creation the token resolves in tiers: a per-agent PAT override if one is set, otherwise your personal token, otherwise the platform-wide global PAT. Your personal token is validated when you save it, stored encrypted, and read live at creation time. See GitHub PAT Setup.
Do I need a GitHub token to build an agent from a public repo?
No. A github:owner/repotemplate that points at a public repository clones anonymously, with no personal access token required. This is source-mode only — the agent can read and run the template but can't push its changes back or use write-dependent features (the working-branch sync heartbeat, fork-to-own) until you add a token. See Creating Agents.
Are my credentials ever stored in Trinity's database?
Agent credentials are not — they are injected as files into the agent's container and never persisted as plaintext rows. What the database does hold is always an AES-256-GCM encrypted envelope: tokens that drive long-lived processes outside any container (Slack, Telegram, and WhatsApp bot tokens, shared subscription tokens, payment credentials, per-agent and per-user GitHub PATs), Credential Vault entries, and the platform's own credentials — the Anthropic API key, the platform GitHub PAT, the Resend email key and the Gemini key from Settings → Integrations → API Keys, plus the Slack app token, client secret, and signing secret — which are stored under <key>_encrypted names, never in cleartext. An install upgraded from an older release re-encrypts a leftover cleartext row the first time it is read and deletes the cleartext copy. See Credential Management.
I upgraded Trinity — do I need to rotate my platform API keys?
You should. Encryption at rest for platform-level credentials protects the database going forward only; backups taken before the upgrade still hold those values in plaintext, so rotate the Anthropic API key, the platform GitHub PAT, the Slack app token, client secret, and signing secret, and the Gemini key once you are on the new release. Save the new values through their dedicated settings sections (Settings → Integrations → API Keys and Settings → Integrations → Slack Integration): the generic PUT /api/settings/{key}route answers 422 for those keys — and for any credential-shaped key (*_api_key, *_token, *_secret, *_pat, *_password, *_credentials) — and names the route to use instead. The Slack client ID is the one reviewed exemption, because it is a public identifier that appears verbatim in the authorize URL. Runbook: Secret settings encryption. See Credential Management.
What is the Credential Vault, and how does an agent use it?
The vault is a platform-level store of named, encrypted credentials that an admin grants to specific agents, so an agent fetches a shared secret by name at runtime instead of carrying its own injected copy — nothing is written into its .env. Entries and grants are managed at Settings → Vault(the tab appears only where the vault is enabled; it requires an entitlement) by an administrator signed in interactively — API keys of any scope are refused — and after a platform encryption-key rotation the tab's key-rotation maintenance control re-encrypts every entry. From inside an agent, two MCP tools exist in every build: list_available_credentials() returns the names and kinds this agent has been granted (never values), and fetch_credential(name) returns one granted value; an ungranted or unknown name comes back as not_granted, and where the vault isn't available the tools say so instead of erroring. Once a value has been fetched, Trinity scrubs it out of everything it persists from the turn — transcript, execution log, response and error columns, notifications, channel reports — replacing every occurrence with ***REDACTED***; that covers values fetched in the last 24 hours and what the platform stores, not the agent's own in-container session files. See Credential Management.
How do I rotate the platform encryption key?
The encryption key (CREDENTIAL_ENCRYPTION_KEY) rotates online, with no downtime and no data loss. In short: back up the database, generate a new key, set it as the primary while moving the old key to CREDENTIAL_ENCRYPTION_KEY_SECONDARY(a decrypt-only fallback), and restart the backend — existing secrets keep decrypting via the old key while all new writes use the new one. Then run the re-encryption script to sweep every database-persisted token onto the new key, and finally remove the secondary key. Per-agent .credentials.enc files re-encrypt on their next credential operation. See Credential Management.
How do I move an agent's credentials to another Trinity instance?
Export the credentials to a .credentials.enc file (Export to Git on the Credentials tab, or the export_credentialsMCP tool), bring that file to the agent's workspace on the target instance, and import it there (Import from Git on the Credentials tab, or the import_credentials MCP tool). The catch is the encryption key: the file only decrypts if the target instance uses the same CREDENTIAL_ENCRYPTION_KEY as the source. An admin can retrieve the key from the source instance (via the encryption-key API endpoint or the get_credential_encryption_key MCP tool) and configure it on the target before importing. See Credential Management.
How do I know which credentials an agent actually needs?
The Credentialstab shows a per-variable checklist built from the agent's own live template.yaml — so a forked or hand-edited agent reports its real requirements, not its original template's. Each row shows what the credential is for, whether it is currently set (probed from the agent's .env; names only, values are never read or transmitted), and a link to where you obtain it. You can fill values in directly on the checklist. It renders for a stopped agent too, with the live-status column honestly marked unavailable. Reading it is owner-only and human-only. See Credential Management.
How does a template declare the credentials it needs?
Two sibling keys in template.yaml. credentials: lists the variable names only and is frozen that way, so older Trinity versions can still read a newer template. The optional credential_setup: decorates each one with title, description, required, secret, format, setup_url, and a non-secret default. Every credential_setup: entry must name a variable that credentials:declares — an entry naming anything else is dropped with a named error while its valid siblings survive. secret defaults to true and setup_urlmust be HTTPS with no embedded userinfo, so a credential is masked until an author says otherwise and a setup link can't impersonate a vendor domain. See Credential Management.
I rotated the platform GitHub token — do I need to restart my agents?
No. Saving a new platform PAT under Settings → Integrations → API Keys propagates it to every running agent that uses it within seconds: the container environment, the workspace .env, and the git credential configuration are all updated, so the rotation takes effect for the agent's next push. Agents carrying their ownper-agent token are deliberately untouched by a global rotation — update those on the agent's Git tab. See GitHub PAT Setup.