Skip to content

Credentials and engines

Thulu does not ship a model key of its own: each workspace uses its own (BYOK). You add that key under “Settings → AI engines” as a profile, and each agent runs with its engine’s default profile or with one you assign it. Separately, the “Credentials” page stores the GitHub, AWS, Google Cloud, Figma and third-party MCP keys that MCP servers use when an agent opens a PR, reads logs or queries a ticket. Both store secrets encrypted and neither shows them again: only a masked hint like …A0eZ. Each has a link to the other at the top.

Both screens are under “Settings”, which opens from the bottom of the sidebar or from your account menu: “AI engines” is under “Workspace” and “Credentials” under “Integrations”. You need the admin role.

Without a default profile for Claude Code, no agent on that engine starts, and the card says so: “No default profile: runs on Claude Code will not start until you add a key”. It is the first thing to do after creating the workspace; the “Setup” button in the top bar lists it as “Model key (BYOK)”. On your own installation, thulu init already asks for this key and creates the profile.

  1. Get the credential outside Thulu. The recommended form is an Anthropic API key (it starts with sk-ant-api), billed to your API account. You can also run Claude through Amazon Bedrock or Google Vertex AI (see Bedrock, Vertex and custom endpoints) or without storing any key, with identity federation.

  2. Open “Settings” and choose “AI engines”. Each engine has a card. Without a profile, the “Default” section shows the “Set default key” button.

    AI engines with the Claude Code card without a default profile
    A new workspace: no engine has a key. Claude Code carries the "Default engine" mark, the one agents that do not pick an engine use.
  3. Click “Set default key” on Claude Code. The name is filled in (default-claude-code) and “Default for Claude Code” is checked.

  4. Under “Credential” choose “API Key” and paste it into “Key”. Leave “Model” empty to use the CLI’s (sonnet) or type opus or haiku.

    Default profile modal for Claude Code with provider Anthropic API, credential API Key and the key pasted in
    Model, effort and base URL are optional.
  5. Click “Create profile”. The notice “Profile "default-claude-code" created” appears and Thulu asks the provider whether it accepts the key: “The provider accepted the key of …” or “The provider rejected the key of …: check it before the next run”. The card shows the profile with the key hint, its status and which agents use it. Claude Code agents that have no profile of their own now run with this key.

The check asks for the provider’s model list, so it works for API keys. A subscription token or a cloud credential does not answer that list and its profile stays “Not checked”. If a run gets a refusal from the provider, the profile goes to “Refused on a run” with the HTTP code. “Re-check” repeats the test.

A named profile is useful when an agent needs a different model, a different key (for example, another team’s, to separate costs) or a different endpoint. Agents do not use it until you assign it.

  1. On the engine’s card, click “New profile”.

  2. Fill in “Name” (for example opus-reviews), “Model” (opus), “Effort” (“high”) and the “Key”. Leave “Default for Claude Code” unchecked.

  3. Click “Create profile”. The profile appears under “Other profiles” with “No agent uses it”.

  4. Assign it from Agents: pick the agent, open its “Settings” tab and, in the “Model & credentials” box, leave the mode on “Profile”, pick the profile from the list and click “Save settings”.

    Model & credentials box of an agent with the profile opus-reviews selected
    On the agent, the profile decides engine, model and key. The gray box below says what the saved settings run with.
Claude Code card with the default profile default-claude-code and the profile opus-reviews
Agents without a profile of their own use the default; opus-reviews is used by reviewer. Each row shows model, effort, key hint and last use.
Agent configuration Engine and model Key
“Profile” → “Default for Claude Code” Those of the default profile The default profile’s. If someone changes the default, the agent changes with it
“Profile” → a named profile Those of that profile That profile’s. Editing the profile changes every agent that uses it
“Custom” Whatever you choose in “Engine”, “Model” and “Effort”; empty takes the default Always the engine’s default profile’s

Agents never store a key of their own. The details of the “Model & credentials” box are in Agents. If the person who launches the run connected their personal login, that run uses the login instead of the profile’s key.

  • “Make default” on another profile asks for confirmation and says how many agents change (“1 agent without a profile of their own switch to this key and model on their next run”).
  • “Edit” leaves the key empty: if you paste nothing, the stored one is kept. On the default, the checkbox is locked; to stop it being the default you have to make another profile the default.
  • “Delete” does not let you remove a profile that an agent uses: first move those agents to another profile. Deleting the default leaves the engine without a key, and the confirmation says so.

Changes apply from the next run. A run in progress continues with what it started with.

In the Claude Code modal, “Provider” offers “Anthropic API”, “Amazon Bedrock” and “Google Vertex AI”. Each shows different fields:

Provider Fields Notes
Anthropic API “Credential”, “Key”, “Base URL” (optional) and “Send the key as” (appears when you type a base URL) The base URL points at a proxy such as LiteLLM. “Authorization: Bearer” is for gateways that do not accept the x-api-key header. With a base URL, Thulu does not check the key’s prefix
Amazon Bedrock “Region”, “Small model” (optional), “Access key ID” and “Secret access key”, “Session token” (optional) or “Bedrock API key (optional)” With the credential fields empty it uses the installation’s cloud identity (IRSA), if the operator enabled it
Google Vertex AI “Region”, “Project ID”, “Service account key JSON” Same as Bedrock: empty uses Workload Identity
New profile modal for Claude Code with provider Amazon Bedrock, region us-east-1 and the access key fields
A profile through Bedrock. "Model" takes the id Bedrock gives the model or an inference profile.

The OpenAI Codex and OpenCode cards follow the same steps, with “OpenAI API” or an “OpenAI-compatible API” (DeepSeek, OpenRouter) as the provider.

A Claude Code profile against the Anthropic API can authenticate without storing any key. Under “Credential” choose “Workload identity federation”: each run receives an identity token that the daemon signs, and Anthropic exchanges it for a short-lived access token according to a federation rule in the Claude Console. Anyone who reads a container’s environment gets a token that expires with the run.

It needs three things:

  • A fixed https address for the daemon, which is the token issuer: OCTOPUS_WORKLOAD_IDENTITY_ISSUER or OCTOPUS_DOMAIN. With neither, the profile is not saved. Once registered with Anthropic, it is best not to change it.
  • In the Claude Console, register that issuer, create a service account and a federation rule that filters by the subject prefix the form shows, so the rule admits only this workspace’s runs. If Anthropic cannot reach the daemon over the internet, choose inline JWKS and paste the key set the form shows.
  • In the profile, the rule’s IDs (fdrl_…), the organization’s, the service account’s (svac_…) and, only if the rule covers several Anthropic workspaces, the workspace’s (wrkspc_…).

The issuer token’s maximum lifetime at Anthropic has to cover the run’s time limit (see below). It does not work for Bedrock or Vertex.

On a Docker installation, “AI engines” shows the “Your own engine login” panel. “Connect” opens Claude’s sign-in page, you approve with your account and paste the code it shows you. From then on, the runs you start use that login instead of the workspace’s key, one at a time: the others wait in the queue. Runs started by automations, agent mentions or API keys keep using the workspace’s.

“Disconnect” signs the login out and deletes its volume. If a run is still using it, wait for it to finish.

At the bottom of “AI engines”, “Run time limit” says how many minutes an agent run can last in this workspace before Thulu stops it and says so on the task. Without a value of its own, the installation’s applies, and the workspace cannot exceed the maximum the installation sets. “Use default” clears the workspace’s own value. Only an admin changes it.

The “Credentials” page stores the keys MCPs use on an agent’s behalf: argus-github for PRs and Actions, argus-cloud for logs and metrics, argus-figma for reading designs, and the third-party MCPs registered in MCPs. Thulu checks each one when you save it where the provider allows, finds out what permissions it has and ties it to the projects or environments you choose.

Provider Types What for
GitHub “Personal access token” PRs, Actions and git when the project does not use the GitHub App
AWS “Access keys” argus-cloud
Google Cloud “Service account key” argus-cloud
Figma “Personal access token” argus-figma, read-only
“HTTP header (API token)” “Bearer token”, “User and API token (Basic)”, “Custom header” A third-party MCP that accepts a fixed token (Jira with an Atlassian token, for example). There is no generic check: it stays “Not checked” until a call uses it
“OAuth connection (MCP server)” “Connection to an MCP server” A third-party MCP that asks for OAuth (Slack, Atlassian, Linear). You connect it with “Connect” and the daemon stores and renews the tokens
Credentials page with github-store and aws-staging valid, figma-design expiring, the GitHub App panel not connected and the table of recent decisions
Three credentials with their identity, state and what they reach. Below, each time an agent used (or tried to use) one, with the reason if it was refused.
  1. Create the key at the provider. For GitHub, a personal access token. Classic ones report their scopes and Thulu maps them to tools: repo enables PRs and Actions, public_repo only PRs on public repos; add workflow if agents edit .github/workflows. Fine-grained tokens are accepted, but GitHub does not report their permissions and all the tools stay enabled. For Figma, a token with current_user:read, file_content:read, file_comments:read and projects:read.

  2. Under “Credentials”, click “New credential”.

  3. Enter a “Name” (agents see it, for example github-store), pick the “Provider” and paste the fields it asks for: “Token” for GitHub or Figma, “Access key ID” and “Secret access key” for AWS, “Key file (JSON)” for Google Cloud. For a third-party MCP, the name has to be the same one its registration asks for under MCPs.

  4. Under “Which tasks can use it”, check the projects or environments. An environment marked “production” shows in red. “Every task in this workspace” reaches everything, and shows in yellow in the list.

    New credential modal with name github-store, provider GitHub, the token pasted in and the project web-store checked
    A GitHub token is tied to the project (web-store). A cloud key is best tied to its environment: tied to the project, any task of that project can use it.
  5. Click “Check and save”. The modal shows the result: state, identity, how many permissions it found and how many tools are available. “Done” closes; “Add another” goes back to the form.

  6. If it is a GitHub token to clone and push, the result reminds you: “Use it in a project: open Repository → GitHub access and pick it.” (Git and GitHub).

Saving without checking any access is valid, but the credential is useless until you choose something: the notice and the “Access” column say “No access yet”. If Thulu cannot reach the provider, the credential is saved anyway as “Not checked” (see Common problems).

Click a row to open the detail. At the top are “Re-check” and “Disable”; below, the identity, the key hint, the expiry and the last check.

Detail of the credential github-store filtered by run_: in the Actions group, run_rerun, run_cancel and run_dispatch grayed out because the key lacks github:actions:write
Grayed rows ask for a permission the token does not have (here github:actions:write). You turn the rest on or off; "Save changes" applies.
  • The tool list is grouped into “Read”, “Write” and “Actions”, with a search box (“Search tools”) and a checkbox per group to turn them all on or off.
  • To keep any agent from using a tool with this key (for example pr_merge), uncheck it and click “Save changes”.
  • “Which tasks can use it”, at the bottom of the detail, changes the access.
  • “Rotate key” replaces the secret without touching who can use it or which tools stay on. “Rename” changes the name.
  • “Disable” turns the whole credential off without deleting anything. Tasks keep starting, without those tools.
  • “Delete credential” removes the secret, the access and the tool settings. The key stays valid at the provider: revoke it there too.

The “Recent decisions” panel lists each tool call that asked for a credential: when, “Allowed” or “Refused”, the tool, the credential, the task and the reason (“the key lacks the permission”, “no credential reachable for that resource”, “several candidates; the agent must name one”). “Refusals only” filters.

State What happens
“Valid” The provider accepted it
“Expiring” / “Expires Oct 20” It has an expiry date coming up (temporary AWS credentials, GitHub tokens with an expiry)
“Expired” / “Invalid” A task that needs this credential for its tools does not start: a “Launch blocked” comment is left with the credential and the affected tools
“Not checked” Thulu could not ask the provider, or the type has no check (HTTP header). The detail warns: “Could not find out what this key allows: every tool stays enabled.”
“Disabled” You turned it off. It does not block: the task runs without those tools

Thulu re-checks each credential by itself every 6 hours. To launch a task with an expired credential, rotate it or disable it: once disabled, the run starts without the tools that depended on it.

The “GitHub App” panel on this page connects an App that replaces personal tokens for git: it mints a short-lived token per operation, limited to one repository. It serves every workspace of the installation, so connecting or removing it belongs to an admin of the operator workspace. On the SaaS the App comes connected and you only install it on your organization. On your own installation, “Create the App on GitHub” opens GitHub’s form with the permissions, the webhook and the URLs already filled in, and comes back with the App connected; “Connect an existing App” asks for the “App ID” and the .pem of an App registered by hand. The full steps are in Git and GitHub.

If the App was configured with environment variables (OCTOPUS_GITHUB_APP_ID and the others), the panel shows it as “From environment” and does not let you change it from the UI.

Symptom Cause and way out
The run does not start: “no LLM credential for … add a default profile for … in Settings → AI engines” The agent’s engine has no default profile. Add it under AI engines
“The AI engine rejected the credential (HTTP …)” on the task The provider did not accept the key on the run. The profile goes to “Refused on a run”: edit it and paste a new key
“API key starts with sk-ant-api” when creating a profile You pasted a token of another kind. Change “Credential” or the key and click “Create profile” again
The agent’s box says the settings have no key, or the selector shows “no key: will not start” That engine has no default profile
“"opus-reviews" is used by reviewer. Move those agents to another profile first.” The profile has agents assigned. Change them under Agents and delete again
A new credential stays “Not checked” with “Could not reach …” Thulu did not reach the provider (network, proxy, DNS). Click “Re-check” once there is outbound internet
An agent says it cannot dispatch a workflow Look at “Recent decisions” with “Refusals only”: “the key lacks the permission” is the token (a classic one needs the repo scope, not only public_repo); “not offered at this stage” is the agent’s MCP configuration (MCPs)
A federated profile is not saved OCTOPUS_WORKLOAD_IDENTITY_ISSUER or OCTOPUS_DOMAIN is missing on the daemon
New credential result with state Not checked, Can do Not discoverable and a note with the network error
What you see if Thulu cannot reach GitHub when saving: the credential is saved anyway, with no permissions found and all the tools enabled.