# Ona Changelog
Source: https://ona.com/docs/changelog
Product updates and announcements
## Compare Automation models and usage per run
Choosing an Automation model is easier when you can compare what each run used. Anyone who can view an Enterprise Automation run can now see its effective model and reasoning effort. Organization admins, Automation admins, and eligible Billing Viewers also see final Intelligence usage.
Open an Automation's **Execution History** and select a completed run. Managed usage appears in credits, while bring-your-own-key usage uses configured prices or falls back to token counts when rates are missing.
[Learn how Automation run usage is calculated](/docs/ona/automations/running-automations#execution-history)
## What else we've shipped
* Environment inventory filters now live in table headers, remain available on narrow screens, and persist in the URL for sharing.
* New direct LLM integrations now use AWS Bedrock, AWS Bedrock Mantle, or OpenAI, while existing Anthropic and Google Vertex AI integrations remain editable.
* Runner settings now use consistent lists and actions for providers, repository access, and environment classes.
* Automation execution histories load faster as the number of retained runs grows.
* OpenAI integration forms no longer show a model selector when there is only one available option.
* VS Code and the CLI now show each port's effective admission level.
* Dashboard dropdowns now handle pointer clicks reliably, including in secret creation forms.
* Linear integrations now start the correct OAuth flow on first enable, while GitLab merge request Automations run only when commits are pushed.
* Concurrent secret changes now propagate reliably to every affected environment.
* Python SDK event streams now deliver updates as they arrive, including environment lifecycle and agent wait events.
* Terminals recover after an environment restarts, and environment headers report lifecycle status without agent activity overriding it.
## Queue and steer Codex while it works
Long Codex sessions no longer make you wait to share the next instruction. You can send follow-up prompts while Codex is running, see them in a queue, and steer the session toward the work that matters next.
Review or remove pending prompts before Codex processes them. The conversation outline stays visible for supported sessions, so you can jump between turns as the thread grows.
Generally available.
## What else we've shipped
* File links in Codex responses now scroll the selected line into view.
* Slack links and agent access tokens use the correct origin for organizations with custom domains.
* Multiline slash commands preserve their review context when Codex expands them.
* Custom environment classes once again show the instance type selector.
* Environment inventory pagination remains clickable when the support launcher is hidden.
## Send user details to your model gateway
Organizations that route Codex through an OpenAI-compatible gateway can now add request headers for each environment creator. Use them to route requests, apply gateway policies, or attribute model usage without maintaining a separate user mapping.
Configure a fixed header or build one from signed identity details such as the creator's email or identity-provider attributes. Ona resolves these values when a conversation starts. If it cannot resolve one header, the conversation continues with the remaining headers.
[Learn how to add custom request headers](/docs/ona/agents/llm-providers/openai#add-custom-request-headers)
## What else we've shipped
* Codex Goal sessions resume more reliably after an agent restart.
## Run Automations with parameters
Manual Automations can now ask for the inputs they need before a run begins. Add a named parameter such as `{{ .Parameters.ticket_id }}` to a prompt, command, pull request field, or agent context.
When you click **Run**, Ona opens **Run with options** and requires a value for each parameter. You can also choose different projects or repositories for that execution without changing the Automation.
Parameters work through the API too, so external tools can start the same Automation with different inputs.
[Learn how to run an Automation with parameters](/docs/ona/automations/running-automations#run-with-parameters)
## What else we've shipped
* `ona environment port open` now requests creator-only port access by default, while older runners fall back to public access with a warning.
* Organization settings now separate policy and security controls while grouping secrets with other environment settings.
* Cost & Budgets pre-fills published prices for supported OpenAI models when you configure your own provider key, without replacing saved rates.
* Live conversations display updated responses without retyping, prevent duplicate question responses, and recover file diff rendering reliably.
* OAuth flows and integration links keep custom-domain users on the correct Ona domain, while GitHub reauthentication replaces stale credentials correctly.
* Maximum environment lifetime changes apply to existing environments, and recently changed environment resources refresh without stale state.
* Codex preserves each conversation's model routing and resumes Goal sessions reliably.
* Sidebar search remains readable in dark mode, and environment file searches expand to use the available space.
## Search sessions from the sidebar
Busy sidebars make the session you need hard to spot. You can now search sessions by environment name or ID, branch, repository, project, and agent task details.
Search works across **Project** and **Recently active** views while keeping related parent and child sessions together.
## What else we've shipped
* Core and Enterprise members can choose a default auto-stop timeout from **Account Settings > Preferences** for newly created environments unless a timeout is set explicitly.
* The AI home prompt now has compact controls for choosing a project, repository URL, or existing environment before starting work.
* The CLI can archive one or more environments by ID or name with `ona environment archive`, and uses the current environment when no reference is given.
* Editor, OIDC, billing, and general settings pages now use consistent page headers, actions, and mobile layouts.
* Conversations with large environment log histories load faster and use less browser memory.
* Codex model choices and context window settings stay consistent while settings and policies load and after a run starts.
* Enterprise members can open Automations shared with them and follow direct links even when they cannot create new Automations.
* Large organizations can grant the Projects Admin role reliably, including across thousands of projects.
* Custom OpenAI-compatible endpoints keep their configured path prefixes when Ona sends Responses or Chat Completions requests.
* VS Code on Windows preserves quoted Ona SSH proxy commands, so Remote SSH connections open correctly.
## Connect multiple GitHub organizations
Repositories do not always live under one GitHub organization. You can now connect one Ona organization to multiple GitHub organizations through the Ona GitHub App.
Add each installation from **Organization Settings > Integrations**, then choose the matching `github.com/` source when configuring a pull request-triggered Automation. Each installation can be enabled, disabled, or removed independently.
The built-in Ona service account uses GitHub App credentials for repositories covered by each installation, so PR review Automations do not need a separate personal access token.
[Learn how to connect GitHub organizations](/docs/ona/integrations/configure-github)
## Pin sessions in the sidebar
You can now pin active sessions in the sidebar to keep important work easy to find as you continue iterating.
Pinned sessions stay at the top of both **Project** and **Recently active** views, so you can jump back into ongoing work without digging through your session history.
Pinning a session does not change its environment retention or lifecycle policy.
## Pull usage data through the API
Enterprise teams can now pull more usage data out of Ona without opening the dashboard. New API and SDK access covers AI cost usage and Insights metrics, so platform teams can feed spend, adoption, co-authoring, agent trace, and pull request trends into their own reports.
Use personal access tokens or service accounts with the right billing or insights viewer role. The Insights API is documented with copy-pasteable requests and examples for each endpoint.
## What else we've shipped
* Organization policy settings are easier to scan, with environment, project, security, command, and identity controls grouped in the newer settings layout.
* Agent policy settings now use clearer sections and inline availability controls.
* Members and service accounts now see a more consistent integration authentication flow.
* Billing pages stay available when current balances are temporarily unavailable, and Core subscription setup handles retry cases correctly.
* Insights API `userId` filters scope results to one user instead of returning organization totals.
* Conversations with older history now show visible messages correctly while earlier messages load.
* Interrupted agent runs recover more reliably instead of leaving an agent busy.
## Claude Sonnet 5 is now available
Anthropic's latest model, Claude Sonnet 5, is now available on Ona Cloud and Enterprise. On Cloud, the next time you start the Ona agent it uses Sonnet 5 automatically. On Enterprise, availability depends on your administrator's configuration.
Sonnet 5 brings stronger reasoning and coding to your agents with no setup required.
## What else we've shipped
* Linear agents are now available to every organization, so you can drive Ona sessions straight from Linear issues.
* Slack agents are now available to every organization, letting you start and follow Ona sessions from Slack.
* Admins can set a Goal mode policy for Codex agents from organization Agent settings, controlling whether members can run agents in goal mode.
* A page-load notification now tells you when sessions have been archived, with a link to review them and an option to silence future reminders.
* The context window usage popover in the chat footer is clearer, showing context pressure, token rows, and monthly budget at a glance.
* Model colors on the daily usage chart stay consistent from day to day, so a model keeps the same color instead of swapping as spend changes.
* The Codex logo now appears on the Conversation tab as soon as you select a Codex model, even before the first run starts.
* The prompt input is focused automatically when you open a new conversation, so you can start typing right away.
## Switch sessions with keyboard shortcuts
Jumping between sessions no longer means reaching for the mouse. Hold Cmd (or Ctrl on Windows and Linux) and the sidebar reveals a numbered pill on each visible session. Press the matching number, from 1 to 9, to switch straight to that session.
The shortcuts are always on in Ona Desktop. On the web, turn them on from your account preferences, and the same keys work from inside a conversation so you can move between tasks without leaving the one you're in.
## What else we've shipped
* Codex agents now run shell commands inline: prefix a prompt with `!` to execute it as a shell command instead of sending it to the model.
* You can archive an environment directly from its sidebar menu, without opening the environment first.
* GitHub App integrations are now available to all organizations using GitHub.com, so admins can install the App from Organization Settings and use it as a pull request trigger source.
* Dashboard lists load faster and refetch less often across environments, runners, projects, members, secrets, and prompts.
* The "some AI usage is not included in spend" banner on Cost & Budgets now has a button that opens the rate-management dialog directly.
* Stale Gitpod branding in the dashboard has been replaced with Ona branding.
* Conversation file links open the right file even while the environment is still loading.
* Review comments now go to the session you have selected in the conversation.
* SCIM group membership updates handle duplicate member additions correctly, so directory syncs stay reliable.
## Older updates
## User budgets for AI usage
Enterprise admins can now set monthly AI usage budgets for every member of their organization. Set one default budget for all users, then override it for individual users where needed. Budgets cover credit-billed AI usage and model spend through your own provider keys (BYOK), and each user sees their own utilization in the chat input as they work.
Budgets are soft limits for visibility: nobody is blocked when they exceed one. Over-budget users are highlighted on **Settings > Usage**, and budgets are included in CSV exports.
[Learn more about user budgets](/docs/ona/billing/user-budgets)
## Configure archive timing for environments
Admins can now choose when stopped environments move to Archived. Set the organization policy from **Settings > Organization > Policies**, with options from 1 to 30 days.
Enterprise environments archive after 3 days by default. Core environments continue to archive after 3 days and auto-delete 4 days after archival.
[Learn more about archive and auto-delete](/docs/ona/environments/archive-auto-delete)
## What else we've shipped
* Ona now supports Devin Desktop.
* Admins can now disable start-from-scratch environment creation for non-admins while keeping project and Git URL creation available.
* Automation task failures now appear in the environment view, with a direct action to open logs or review failed tasks.
* Agents now have built-in dev container setup guidance for creating or repairing repository development environments.
* Automation names and descriptions can now be edited inline and saved with the rest of the automation draft.
* Autocomplete fields behave more consistently with keyboard navigation and assistive technology.
* Billing, usage, insights, terms, and automation summary pages respond faster.
* Core subscription setup completes faster and shows steadier loading states while payment details are saved.
* Long agent questions scroll correctly instead of overflowing the clarifying-question drawer.
* The dashboard sidebar responds correctly on iPad Safari.
* GitLab merge request listing avoids timeouts on larger projects.
## Read-only billing and insights access
Enterprise organization admins can now assign **Insights Viewer** and **Billing Viewer** roles to groups. Use these roles when finance, customer success, or engineering leaders need reporting access without full organization admin privileges.
Insights Viewers can open **Insights** from the sidebar and review platform usage, Velocity, and AI Adoption data for projects where insights are enabled. Billing Viewers can open **Settings > Billing** and **Settings > Usage** where those pages apply to their organization, but cannot change subscriptions, payment methods, top-ups, or budgets.
[Learn more about organization roles](/docs/ona/organizations/organization-roles)
## What else we've shipped
* Scheduled Automations can now run every weekday, so recurring work can run Monday through Friday without a custom cron expression. Daily schedules are still available for runs that should include weekends.
* The Insights sidebar item now appears for members with the Insights Viewer role, matching direct access to the Insights page.
## Bitbucket Cloud support
Bitbucket Cloud is now available as a source control provider. Ona agents can create, review, and manage pull requests, add inline comments, check CI status, and search repositories in Bitbucket, just like they already do with GitHub and GitLab.
You can also set up automation triggers from Bitbucket webhooks. Trigger automations on PR events (opened, updated, merged) the same way you do with GitHub and GitLab. [Learn more about webhooks](/docs/ona/automations/webhooks#creating-a-webhook).
## What else we've shipped
* Agents authenticate with the `gh` CLI for GitHub API operations, so tools that call the GitHub API directly work without extra configuration.
* Permission checks and role lookups are faster across the dashboard.
* The GitHub App install flow no longer redirects when the app is already installed.
* Agents can restart stopped environments without a false billing error.
* Plan selection no longer flashes during subscription changes.
* Conversations scroll to the latest message on page reload.
* Streaming conversations display all messages reliably mid-response.
* Diff rendering works correctly after a dependency update.
* Automation search returns results correctly when filtering by name.
## Set auto-stop timeouts from the CLI
The CLI now supports an `--inactivity-timeout` flag for environments. Set how long an environment stays running after you stop interacting with it. Useful when scripting environment creation or adjusting timeouts without opening the dashboard.
```bash theme={null}
ona environment create --class-id --inactivity-timeout 1h
ona environment update --inactivity-timeout 3h
```
Request no auto-stop:
```bash theme={null}
ona environment update --inactivity-timeout 0s
```
The same policy enforcement applies as in the dashboard. Values remain subject to your organization's plan and maximum timeout policy.
## What else we've shipped
* Run `/ona:about` to see which tools are loaded, which are available on demand, and which skills are active along with their source.
* Agent conversations restore faster after reconnecting.
* Conversations recover automatically after a brief network interruption without requiring a page reload.
* Agent sessions start reliably and preserve context across multi-step tasks.
* Insights correctly attributes AI-authored code in squash-merged PRs across GitHub, GitLab, and Bitbucket.
* The usage page loads correctly for 31-day months in DST-shifted timezones.
* Project settings save succeeds even when a previously configured environment class was removed.
## Sort the sidebar your way
The sidebar now lets you switch between three views. By default you see the **Project** list you're used to today. Select **Recently active** for a chronological view grouped and sorted by recent activity, or **Archived** to view environments soon eligible for clean-up. Your choice of **Project** or **Recently active** is remembered across sessions.
## What else we've shipped
* The agent's plan steps appear as a live todo list in the conversation.
* The agent explores your codebase faster by reading files concurrently.
* Integration tool failures are now visible in the dashboard status panel.
* Large repositories initialize faster.
* Dashboard pages across billing, integrations, and runner settings load faster.
* Environments stay active while you are using the dashboard.
* Stopping the agent mid-response no longer shows an error banner.
* The agent recovers cleanly after a brief restart without leaving a stale error message.
* Runner availability warnings only appear when a runner is genuinely unavailable.
* Custom domain authentication completes reliably.
## Port authentication is now available
Shared ports now require authentication. When you open a port from the dashboard or CLI, you choose an access level: creator only, organization members, or anyone. Ona validates the visitor's identity before serving the port, so a shared URL no longer means unrestricted access.
Organization admins can cap the maximum admission level from **Settings > Organization > Policies**, preventing members from sharing ports more broadly than policy allows. If a user requests a wider level than the cap, the dashboard disables the option and the CLI rejects the request.
Set the access level in the dashboard's Open Port dialog, or pass `--admission` on the CLI:
```bash theme={null}
ona environment port open 3000 --admission creator_only
ona environment port open 8080 --admission organization
```
See the [port sharing documentation](/docs/ona/integrations/ports) for the full access-level reference and the browser retry flow.
## What else we've shipped
* Agent sessions now show a "Thinking…" indicator while the model is processing, so you can tell the agent is working before any output appears.
* You can filter sessions by project, recently active, or archived status from the sessions list.
* Slash commands like `/clear` and `/support-bundle` are now surfaced in the agent prompt, so you can discover them without memorizing syntax.
* User messages in the agent chat display a footer with the message type, timestamp, and a copy button.
* The prompt textarea now shows a character count and blocks submission when the message exceeds the limit.
* Drag-and-drop reordering in the dashboard now supports full keyboard navigation.
* Typing in the agent prompt textarea is responsive again after a lag that could reach \~1s per character.
* Environments start noticeably faster.
* Error messages when insights prerequisites are missing now describe the actual issue instead of suggesting a retry.
* Idle agent conversations are cleaned up automatically when no longer active.
* The review button in the agent chat now diffs the branch against main, not just uncommitted files.
* MCP tool errors now surface the actual error message so you can act on them.
* The user settings page loads correctly in all configurations.
* Dark mode checkboxes are easier to see with improved contrast for the unchecked state.
* Insights caches now refresh correctly when you toggle project insights on or off.
* New environments created from prebuilds now start with a clean git identity.
## Bring your own Terms of Service to Ona
Enterprise organization admins can now require members to accept a custom terms of service before using Ona. Write the terms in Markdown from **Settings → Organization → Terms of Service**, and members are prompted to read and accept on their next dashboard load.
Editing the text publishes a new immutable version and prompts members to re-accept; earlier versions remain queryable for compliance. Track per-member status under **Settings → Organization → Members → Terms Acceptance**, and export the report as CSV when you need it outside the dashboard.
See the [Terms of Service documentation](/docs/ona/organizations/terms-of-service) for setup, the supported Markdown subset, and the CSV column reference.
## What else we've shipped
* Organization roles now include **Environments Reader**, so service accounts and groups can list every environment in an organization without receiving update or delete access.
* GitHub pull request mentions now understand `@ona-agent stop` and `@ona-agent cancel`, so anyone who can mention the agent can stop an active run on that PR.
* Organization admins can set a maximum port admission level for shared ports, including creator-only, organization-only, and public access.
* GitHub App uninstall events now cancel any active PR-mention sessions for that installation, so runs do not keep retrying after the app loses access.
* Agent runs that lose their runner or stop making progress are now stopped automatically instead of remaining active indefinitely.
* Ports can be deleted correctly when an organization has a restrictive maximum port admission policy.
* GitHub PR mentions clear the watching reaction when a pull request is closed or its branch is deleted.
## Tag @ona-agent on a GitHub pull request
Comment `@ona-agent` on a pull request and an Ona session starts on the PR and replies in the thread. Use it for follow-up changes, missing tests, or fixes you spot during review.
Mentions work in PR comments, inline review comments, and review submissions. The agent reads the PR diff and recent comments, then follows the prompt you wrote alongside the handle. Mention `@ona-agent` on its own and the agent reviews the PR.
Install the [Ona GitHub App](/docs/ona/integrations/configure-github) on your organization to enable it. Available on the Free and Core plans. [Contact sales](https://ona.com/contact/sales) to enable it for Enterprise.
[Learn more about mentioning Ona](/docs/ona/integrations/github-pr-mentions)
## What else we've shipped
* The Ona GitHub App can now drive PR-triggered automations directly, so you no longer need to set up a separate webhook to run automations from pull request events.
* A built-in Ona service account ships with every organization and uses the GitHub App for source control, replacing manually-rotated personal access tokens.
* The terminal in the dashboard is available to everyone, so you can open a shell next to your conversation without leaving the browser.
* `ona insights analyze-pr-stats` now works with GitHub Enterprise, GitLab, and Bitbucket Cloud, on top of GitHub.com.
* You can bulk-select prebuilds on a project's Prebuilds tab and cancel or delete them in one action.
* Register for the [Background Agents Virtual Summit](https://background-agents.com/summit) directly from the dashboard.
* VS Code Desktop and VS Code Browser now open directly into the editor without the embedded Ona environment details and conversation view. The embedded view duplicated the dashboard experience, was constrained by VS Code's webview capability which prevents building a rich user experience.
* Port authentication cookies refresh automatically when they go stale, so previewing a service no longer needs a manual reconnect.
* The environment list is easier to navigate with assistive technologies and offers larger touch targets on mobile.
* The Activity button shows a blue unread dot when the sidebar is collapsed, so you don't miss new notifications.
* The "Run Prebuild" button is clearly labelled instead of just "Prebuild".
* Clarifying questions from the agent render as markdown, so links and code spans display correctly.
* Insights summary cards report the same active-user count as the chart and tab below them.
* The browser panel now has a reconnect button when the preview disconnects.
* The browser address bar accepts `localhost:port` URLs without rewriting them.
* Conversation history downloads reliably, even when an agent run has no captured logs to attach.
## Bring your own MCP servers to your organization
Administrators can now add custom MCP servers to an organization from the dashboard. Enable a server once in [Settings > Integrations](https://app.ona.com/settings/org-integrations) and it becomes available to every member of the org.
The first time a member uses the integration, Ona handles the OAuth handshake with the server. Each user then connects their own account from [User Settings > Integrations](https://app.ona.com/?user-settings=integrations), and agents act with that user's permissions.
See the [MCP documentation](/docs/ona/mcp#custom-organization-mcp-integrations) for setup and current limitations.
## What else we've shipped
* Environments can now issue short-lived OIDC tokens for keyless authentication to AWS, GCP, Vault, and anything else that accepts OIDC trust policies. Configure them in Settings > Login & Identity. New organizations start on OIDC V3 by default.
* Settings in the dashboard are grouped into sections like Login & Identity, Billing, and Agents, so you can find the page you need without scanning a long flat list.
* File paths in chat are clickable now. Jump straight to the file the agent is referring to without copy-pasting.
* Collapsed agent actions show a summary of how many files were read, written, and touched overall, so you get the gist without expanding every step.
* The file tree in the dashboard handles large repositories noticeably faster.
* Attached images in chat render as square, scroll-friendly thumbnails instead of stretching the conversation layout.
* The Create PR button hides itself once the agent has already opened one, so you can't accidentally open a second PR for the same change.
* The CLI log commands now default to print-and-exit, with `--follow`/`-f` to tail. The previous `--no-follow` flag is removed. Scripts that relied on `--no-follow` will need updating.
* Insights default date ranges exclude today, so charts reflect complete days only.
* Your terminal agent selection is remembered between sessions.
* Recent Tasks shows your environment's current name after you rename it.
## A new way to collaborate with Ona
We redesigned the way you collaborate with Ona, focusing around the relationship between you and the agent. Your conversation and the agent's output now live side by side so you can move from exploration to review without rebuilding context.
* Your conversation and code changes sit side by side in a two-panel layout. The agent stops being a separate window you talk to and becomes a partner looking at the same screen you are.
* Leave inline comments on any changed file — they feed directly back into the conversation so the agent can act on your feedback without a context switch.
* Ports, services, and logs move into a collapsible bottom drawer. They stay accessible without competing for the same visual priority as your dialogue or your code.
* Browse your conversation, file changes, and comments even when the environment is stopped. The interface works with whatever context is available so you can pick up where you left off.
* A searchable file tree with inline diffs replaces the previous changes panel — review what the agent touched without switching away from the conversation.
* Purpose-built tabs for conversation, files, and environment give each phase of your workflow a focused view.
## Self-serve GCP Runners
You can now deploy GCP runners directly from the dashboard. A three-step setup wizard using the public [Terraform registry module](https://registry.terraform.io/modules/gitpod-io/ona-runner/google/latest) walks you through generating credentials, defining the module in `main.tf`, and running `terraform apply`. The [GCP runner docs](/docs/ona/runners/gcp/setup) have been updated to match.
Available on [Enterprise plan](https://ona.com/pricing).
## What else we've shipped
* Draw annotations on the browser viewport and send annotated screenshots to the agent with a text comment.
* Agent conversations show a shimmering status indicator during environment startup and while the agent is thinking.
* Right-click any file or folder in the file tree to copy its path to the clipboard.
* Automation services can now be triggered during prebuilds, matching the behavior already available for tasks.
* CLI log commands (`environment logs`, `environment devcontainer logs`, `automations service logs`, `automations task logs`) support a `--no-follow` flag to print existing logs and exit.
* The sidebar create-environment button shows a smooth spinner animation while the environment is being created, then fades out when it finishes.
* VS Code and JetBrains extensions find the `ona` CLI correctly on systems that upgraded from the previous `gitpod` binary name.
* Dragging a non-image file into the chat now explains how to share it via the workspace file explorer instead of showing a generic error.
* Annotated browser screenshots send reliably, even at high display resolutions.
## Install the CLI with Homebrew
The Ona CLI is now available via [Homebrew](https://brew.sh/) on macOS and Linux:
```bash theme={null}
brew install gitpod-io/tap/ona
```
The formula auto-detects your OS and architecture. Updates are handled by `brew upgrade ona`.
[CLI documentation](/docs/ona/integrations/cli)
## What else we've shipped
* Type `@` followed by a filename in the chat input to get file suggestions and insert file references into your prompt.
* Automation triggers now support up to 500 projects and repositories, up from 25 and 100.
* SSO login preserves the return URL and no longer auto-redirects in the desktop app.
* The support widget hides when VS Code fills the browser viewport.
* Idle environments now time out reliably instead of running indefinitely.
* Admins can no longer modify automation steps that run as another user.
## Granola integration
Ona agents can now connect to your [Granola](https://www.granola.ai/) account to search meeting notes, read transcripts, and extract action items. Ask an agent to find a past discussion, pull out follow-ups, or cross-reference a meeting decision with your code, all without leaving the conversation.
An admin enables Granola under **Organization Settings > Integrations**, then each user connects their account in **User Settings > Integrations**. Once connected, agents can query any meeting you own by title, date, or attendee.
## What else we've shipped
* Ona now knows today's date, so time-relative questions like "what merged this week?" work without extra context.
* After completing a recurring task, Ona suggests turning it into an automation you can run on a schedule or on PR events.
* Dev container rebuilds now pause the conversation until the environment is back, instead of continuing while the rebuild runs.
* Image attachments in the chat input persist when you switch between conversations.
* Terminal input is noticeably faster when typing quickly or pasting large blocks of text.
* Members and projects lists show the total result count alongside pagination controls.
* Ona handles long responses gracefully instead of surfacing internal continuation messages in the conversation.
* The sidebar status correctly shows "Waiting for environment" when Ona is waiting for an environment to start.
## Warm pools are generally available
Opening a new environment for a large project can take minutes while the runner provisions an instance and loads your prebuild. Warm pools change that. They keep ready-to-use instances standing by so environments start in seconds instead of minutes.
Enable a warm pool on any project from its [project settings](/docs/ona/projects/warm-pools). Set a minimum and maximum pool size, and Ona keeps instances pre-initialized with your latest prebuild. The number of warm instances scales dynamically based on load, staying within the range you configure.
**What you can do now:**
* **Start environments in \~10 seconds** for projects that previously took minutes, especially large monorepos and heavy dev containers.
* **Set min and max pool sizes.** The pool scales dynamically based on load within the range you set, so you're not paying for idle capacity during off-hours.
* **Instances stay fresh.** Warm pool instances rotate daily so they always run the latest OS and software updates.
Warm pools require an Enterprise plan and a [runner upgrade to the latest version](/docs/release-notes/aws-runner#20260402401). If your runner needs an upgrade, the dashboard will show a prompt. See the [warm pools documentation](/docs/ona/projects/warm-pools) to get started.
## What else we've shipped
* Members and projects lists show the total result count alongside pagination controls.
* Terminal input is noticeably faster when typing quickly or pasting large blocks of text.
* The automation list shows who triggered the last run, not who created the automation.
* The webhook selector dropdown in automation settings no longer appears empty.
* The CLI auth code page now shows visible borders around code blocks.
## Ona can merge pull requests
Ona can now merge pull requests and merge requests directly from the conversation. Ask Ona to merge a PR and it handles the merge method (merge, squash, or rebase), sets the commit message, and deletes the source branch afterward. Works with both GitHub and GitLab, including GitLab's merge-when-pipeline-succeeds option.
This completes the PR lifecycle inside Ona. You can now create a branch, write code, open a PR, review changes, address feedback, and merge, all without leaving the conversation.
## What else we've shipped
* Import a `.env` file to bulk-create secrets on any secrets page. Drag and drop or browse, preview parsed variables, and import them all at once.
* File search in the `All Files` panel now returns a flat, relevance-ranked list with fuzzy matching instead of expanding tree nodes.
* The `Review` button shows a dropdown of your organization's review skills when available, so you can pick a review style without typing slash commands.
* Opening the command palette (Cmd+K) now lists your environments immediately, with running ones sorted first.
* Ona can create new projects directly from a conversation.
* Copy the current branch name from the environment header dropdown.
* The project home page shows live `Speed`, `AI Adoption`, and `Authors over Time` insight cards with real data.
* Insights chart labels and descriptions are clearer, with explanations moved below the graph.
* Press Esc to dismiss the clarifying questions panel.
* Terminal reconnections are smoother, with no visual flicker when resuming a session.
* Environments with persisted file tabs stay stopped until you explicitly start them.
* Cmd+W on macOS hides the Desktop window instead of quitting the app.
* Slack sessions resume automatically after completing OAuth connection.
* Dot-prefixed files and directories now appear in the file tree.
* Automations run more reliably through long multi-step tasks.
## Maximum environment lifetime
The [maximum environment lifetime](/docs/ona/organizations/policies/environment-lifetime) policy is now available to all organizations. Set a maximum age for environments and optionally block restarting expired ones, useful for enforcing security policies, ensuring fresh base images, or meeting compliance requirements for environment rotation.
Configure it under **Settings > Organization > Policies**. Pick a duration (1 day to 6 months), and new environments receive an expiry based on the configured duration. Once an environment passes its expiry, it becomes non-compliant. Turn on **strict enforcement** to prevent users from restarting expired environments entirely. A compliance banner shows how many environments are affected and how many will expire within 24 hours.
## What else we've shipped
* Send individual review comments to Ona from the per-comment dropdown menu, in addition to the existing bulk action.
* Failed environments show a one-click retry button when a transient error prevents them from starting.
* The ports empty state now matches the services UI with clearer guidance on what to do next.
* You can select a default environment class directly on the project details page.
* The dashboard loads faster by deferring terminal resources until you open a terminal tab.
* Disabled actions now show a tooltip explaining why they are unavailable when the agent is working.
* Environments can be restarted from the dashboard while still stopping.
* SSH tunnels through ports work without requiring separate authentication.
* The diff viewer handles lines starting with "--" correctly.
* Port access tokens now last 24 hours instead of expiring prematurely.
* File search in environments skips .git and node\_modules directories.
* Agent conversation history is preserved when the runtime shuts down.
## Live secret propagation
Secrets now propagate to every environment in their scope the moment you create, update, or delete them. Organization secrets reach all environments in the org. Project secrets reach all environments in the project. User secrets reach all environments for that user.
File-based secrets and container registry credentials update in place. Environment variable secrets may need a dev container rebuild — when that happens, a prompt appears in VS Code and the dashboard with a one-click rebuild button.
## What else we've shipped
* [Personal access tokens](/docs/ona/integrations/personal-access-token) can now be scoped to read-only or read & write access.
* Service account tokens can now be set to never expire or expire after one year.
* Dashboard tables have sticky headers and a floating action bar for working with multiple items at once.
* Credit auto top-up is now available to all organizations on the core tier.
* Environments start noticeably faster.
* A new Audit Log Reader role lets you grant read-only access to your organization's audit logs.
* Resource usage warnings are clearer and include suggestions for what to do next.
* Secrets added or changed while an environment is running now appear inside the container without a restart.
* Repositories with submodules now clone correctly in more environment configurations.
* Scheduled automations run more reliably on their configured schedule.
## Faster, smoother, more helpful
This week we focused on speed, onboarding, and fixing the small things that add up. Environments start faster. The CLI is more forgiving. And if you're new to Ona, the product now meets you where you are.
**Environments start faster.** Internal caching improvements shave time off every environment start. The dashboard sidebar also loads noticeably quicker.
**Getting started has fewer steps.** GitLab users can now sign in during onboarding with one click. GitHub users skip a redundant login because Ona reuses your existing credentials for Git access. And if your repository doesn't have an environment configuration yet, a notification guides you through creating one.
**The CLI speaks your language.** Reference environments by the first few characters of their ID instead of copying the full UUID.
## What else we've shipped
* Prebuild details now show how much disk space each snapshot uses.
* Automations can now be created and managed through the API.
* The environment details page has a cleaner layout for services, ports, and tasks.
* When a runner is having issues, a direct link to download diagnostic logs appears in the dashboard.
* The CLI reconnects automatically when a connection drops instead of hanging silently.
* SSH connections work correctly when Ona is installed in a folder path that contains spaces.
* Questions from the agent now appear outside collapsed sections, so you never miss a prompt that needs your input.
* Code changes update in real time in the session panel.
* When no machines are available, the error message now explains what happened and what to do next.
## Plan mode
Start every task with a plan. Plan mode adds a structured planning phase to Ona sessions where the agent gathers requirements through interactive questions, writes a specification, and waits for your approval before writing any code.
Select "Plan" from the mode dropdown in the session input or from the home screen. Describe your task, and the agent asks clarifying questions as clickable multiple-choice options. Pick a choice, type a custom answer, or skip. Once the agent has enough context, it writes a `spec.md` with the full implementation plan. Review the spec, then click **Build** (or press `Cmd+Shift+Enter`) to start implementation.
Available on all plans.
## What else we've shipped
* Forward environment ports to your local machine with `ona environment port forward`.
* Ona prompts you to rebuild the dev container when you change a secret, so the new value takes effect immediately.
* PR links and preview URLs now appear as clickable outputs in the session.
* Environments start faster, especially for repositories with many files.
* Sessions with screenshots respond faster.
* A banner in the session view suggests converting a repository to a project for faster startups.
* Long-running agent tasks no longer disconnect mid-stream.
* The CLI reconnects automatically instead of hanging on a dropped connection.
* Stale action buttons are cleared when they no longer apply.
## Code review experience
Review code changes and request reviews from Ona directly in the session.
**Leave inline comments** — Review Ona's work by leaving inline comments in the code changes panel, just like reviewing a PR. Highlight the relevant code lines, leave your questions or feedback, and send them off to Ona. Ona will act on the comments accordingly.
**Request a review from Ona** — Ask Ona to review the current code changes before merging. Ona examines the diff, leaves inline comments with suggestions, and flags potential issues — giving you a second pair of eyes without waiting for a teammate.
**Create a PR directly** — Once you're happy with the changes, create a pull request straight from the session. No need to switch to your Git provider — Ona commits, pushes, and opens the PR for you.
## Organization skills
[Agent Skills](https://agentskills.io) now work at the organization level. Create reusable skills that Ona Agent discovers and uses proactively across every session in your organization. Skills capture your team's best practices (code review checklists, test strategies, deployment procedures) and share them with everyone.
**What you can do:**
* **Create and edit skills** with a name, description, and prompt. The description tells the agent when to apply the skill automatically.
* **Optional slash commands.** Toggle a `/trigger` so users can also invoke a skill manually in the chat.
* **Import defaults.** Start with a curated set of skills (Pull Request, Documentation, Explain Code, Catch Up) and customize from there.
* **Search and filter.** Find skills by name, description, or trigger.
* **Migrate legacy commands.** Existing slash commands can be migrated to skills with one click, preserving their trigger while enabling proactive discovery.
Manage skills from **Settings → Agents** in the dashboard.
[Learn more about organization skills](/docs/ona/skills)
## Organization roles for groups
Delegate administrative responsibilities in your [Enterprise](https://ona.com/pricing) organization without granting full admin access. Assign organization roles to [groups](/docs/ona/organizations/groups) so team members can manage specific resource types across the organization.
**Available roles:**
| Role | Grants admin access to |
| --------------------- | ---------------------- |
| **Runners Admin** | All runners |
| **Projects Admin** | All projects |
| **Groups Admin** | All groups |
| **Automations Admin** | All automations |
Toggle role checkboxes directly in the groups table under **Settings → Members → Groups**. When a role is assigned, all group members immediately receive admin permissions on existing and future resources of that type.
[Learn more about organization roles](/docs/ona/organizations/organization-roles)
## Automations
Automations execute multi-step workflows across your repositories — from routine maintenance to large-scale refactoring. Define steps, choose a trigger, and let them run in isolated environments with your tools, dependencies, and guardrails.
**How it works:**
1. **Define** — Combine steps in sequence: prompts (agent-driven tasks), shell scripts, pull request creation, and report extraction
2. **Trigger** — Run manually, on pull request events via [webhooks](/docs/ona/automations/webhooks), or on a [time-based schedule](/docs/ona/automations/triggers/timebased)
3. **Execute** — Run across repositories in parallel, each action in its own isolated environment
4. **Review** — Monitor progress in real time, inspect logs, and approve PRs before merging
**Templates** — Start from pre-built templates for common workflows: Sentry error triage and fix, 10x engineer (picks up your top Linear issue and delivers a PR), code review, and more. Templates are gated on required [integrations](/docs/ona/integrations/overview), so you only see what you can run.
**Sharing and access control** — Share automations with everyone in your organization, individual users, or [groups](/docs/ona/organizations/groups). Assign roles to control what recipients can do:
| Role | Permissions |
| ------------ | --------------------------------------------- |
| **Admin** | Edit, delete, share, run, view all executions |
| **Executor** | Run and view own executions |
| **Viewer** | Read-only access |
**Service accounts** — Run automations as a [service account](/docs/ona/organizations/service-accounts) for scheduled and event-driven workflows. Commits and PRs appear under the service account identity, separating automation work from human work.
**Guardrails** — Control execution with concurrency limits, total action caps, [command deny lists](/docs/ona/command-deny-list), environment isolation, and [audit logging](/docs/ona/audit-logs/overview).
**Webhooks** (Enterprise) — Create standalone [webhook](/docs/ona/automations/webhooks) endpoints for GitHub or GitLab. Scope to a repository or organization, and reuse a single webhook across multiple automations.
**Availability** — Automations are available on Core and Enterprise plans with [plan-based limits](/docs/ona/automations/plans-and-limits) on automations, concurrent actions, and features like webhooks.
[Learn more about automations](/docs/ona/automations/overview) · [Create your first automation](/docs/ona/automations/configure-automations) · [Automations in practice](/docs/ona/automations/automations-in-practice)
## SCIM provisioning (beta)
Ona now supports SCIM (System for Cross-domain Identity Management), letting your identity provider automatically create, update, and deactivate user accounts. Link SCIM to an existing SSO provider, and directory changes in your IdP are reflected in your Ona organization without manual intervention.
Currently supported identity providers:
* **Microsoft Entra ID**
[Learn more about SCIM provisioning](/docs/ona/scim/overview)
## New MCP integrations: Atlassian, Notion, and Sentry
Ona Agent now supports three new MCP integrations — Atlassian, Notion, and Sentry. Once enabled by an organization admin and authenticated by individual users, agents can interact with these services directly from sessions.
* **Atlassian** — Manage Jira issues, search Confluence, and link code changes to tickets. [Configure Atlassian](/docs/ona/configure-atlassian)
* **Notion** — Search pages, read documentation, and access project wikis. [Configure Notion](/docs/ona/configure-notion)
* **Sentry** — View errors, analyze stack traces, and track regressions. [Configure Sentry](/docs/ona/configure-sentry)
You can check the status of all MCP integrations — including connection errors and warnings — using the **MCP Integrations** button in the session input.
[Learn more about integrations](/docs/ona/integrations/overview)
## Secrets available during Dev Container builds
Organization and project secrets may now be used during Dev Container image builds via [secret mounts](https://docs.docker.com/build/building/secrets/#secret-mounts) — without baking them into the final image.
Each `RUN` step in your Dockerfile must explicitly request the secrets it needs:
```dockerfile theme={null}
FROM node:20
RUN --mount=type=secret,id=/usr/local/secrets/npm-token,target=/tmp/npm-token \
echo "//registry.npmjs.org/:_authToken=$(cat /tmp/npm-token)" > .npmrc && \
npm ci && \
rm -f .npmrc
```
User secrets are not available during builds because built images are cached and shared across the project, so personal credentials could be exposed to other team members. Docker Compose mode is not yet supported.
[Learn more about using secrets during builds](/docs/ona/configuration/devcontainer/overview#using-secrets-during-builds)
## Ona now runs on Claude Opus 4.6
We've upgraded Ona to Claude Opus 4.6, Anthropic's latest flagship model. At the same price as Opus 4.5, you'll see significantly better results across a range of tasks, especially for complex problems.
**What's new**
* **Adaptive thinking** - The model decides when to think deeper, no manual tuning needed.
* **More output tokens**: Twice the previous limit, better for large refactors and file generation.
* **Improved tool use**: More accurate code edits and fewer mistakes.
The upgrade is live now. No action needed on your end. Credits will be consumed at the same rate as before. [**Try now**](https://app.ona.com).
## AWS eu-south-2 region now supported
You can now install a Runner in AWS region `eu-south-2` (Spain). When you do, a default environment class is created: **Extra Large (Spot)**. From there, you must configure additional environment classes as custom classes.
For `eu-south-2`, we recommend using instance types from the `m7i` (compute) and `g6` (GPU) families.
**Getting started:**
* [Default Classes](/docs/ona/runners/aws/environment-classes#default-classes)
* [Creating Custom Classes](/docs/ona/runners/aws/environment-classes#create-custom-classes)
* [Requirements](/docs/ona/runners/aws/environment-classes#supported-instance-types)
* [AWS instance types by region](https://docs.aws.amazon.com/ec2/latest/instancetypes/ec2-instance-regions.html#instance-types-eu-south-2)
## Automatic credit top-ups
Core plan organizations can now enable automatic credit top-ups. When your credit balance runs low, Ona automatically purchases additional credits using your default payment method.
Enable auto top-up and choose a top-up amount at **Settings → Billing**.
[Learn more about auto top-up](/docs/ona/billing/overview#automatic-credit-top-up)
## Service account tokens and secrets
Service accounts now support tokens and secrets, enabling programmatic API access and secure credential management for automations.
**Tokens** — Organization admins can issue long-lived tokens (up to 90 days) on behalf of service accounts. Use these for CI/CD pipelines and external scripts that need to start automations or query the API.
**Secrets** — Attach secrets to service accounts. When an environment runs with a service account identity, those secrets are automatically injected.
[Learn more about service accounts](/docs/ona/organizations/service-accounts)
## Share resources with individual users
Sharing a project with a colleague no longer requires creating a group or asking an org admin. Resource admins can now share directly with individual users.
**What's new:**
* **Project creators become admins** — Creating a project automatically makes you its admin. This aligns with how runners and automations already work.
* **Share with individual users** — Admins of projects, runners, and automations can now share directly with individual users. No group required.
* **Share with existing groups** — Previously, only org admins could share resources with groups. Now any resource admin can share with groups, even if they are just a member of the organization.
[Learn more about sharing resources](/docs/ona/organizations/sharing-resources)
## Home Notices
Organization admins can now display notices to communicate important information to all organization members on the Ona home page.
**What's new:**
* **Admin settings page**: Configure notices from Settings → Organization → Announcements
* **Markdown support**: Format messages with bold, italic, and links
* **Live preview**: See exactly how your notice will appear before publishing
* **Toggle control**: Quickly enable or disable the notice without losing your message
**Getting started:**
1. Navigate to **Settings → Organization → Announcements**
2. Enable the home notice toggle
3. Enter your message (up to 1,000 characters)
4. Click **Save** to publish
This feature is available exclusively to Enterprise customers. [Learn more about home notices](/docs/ona/organizations/announcement-banner).
## CLI: Action Required - Force Update
A recent CLI release contained a version format issue that breaks automatic updates. If your CLI shows a version like `main-gha.XXXXX` when running `gitpod version`, auto-update will not work.
**To fix**, run:
```sh theme={null}
gitpod version update --force
```
After updating, `gitpod version` should show a version in the format `YYYYMMDD.HHMM.N` (e.g., `20260120.0512.0`).
Read more about the CLI in its [documentation](/docs/ona/integrations/cli).
## JetBrains Warmup for Prebuilds
Prebuilds now support JetBrains warmup, significantly reducing editor startup time for JetBrains users. When enabled, prebuilds download and install the JetBrains backend and build project indexes ahead of time.
**What's new:**
* **Backend pre-installation**: JetBrains backend is downloaded and installed during prebuilds
* **Index building**: Project indexes are built during prebuilds using the JetBrains warmup command
* **Recommended editors**: Configure which editors to recommend for your project, which also determines which JetBrains editors to warm up
**Benefits:**
* Skip editor backend download when opening JetBrains editors
* Instant code navigation and analysis with prebuilt indexes
* Consistent experience across all team members
**Getting started:**
1. Enable JetBrains warmup in your project's prebuild configuration
2. Configure [recommended editors](/docs/ona/projects/recommended-editors) to specify which JetBrains editors to warm up
3. Trigger a prebuild to create a warmed-up snapshot
[Learn more about JetBrains warmup](/docs/ona/projects/prebuilds#jetbrains-warmup)
## Claude Opus 4.5 for Ona Cloud
Ona Cloud users now have access to Claude Opus 4.5 for new agent sessions. This model upgrade brings improved reasoning and code generation to your development workflows.
**What's new:**
* New agent sessions on Ona Cloud now use Claude Opus 4.5
* Existing sessions continue with their original model
**Getting started:**
* Start a new session with Ona Agent to use Claude Opus 4.5
* [Learn more about Ona Agents](/docs/ona/agents/overview)
## Agent Skills support
Ona Agent now supports [Agent Skills](https://agentskills.io) - an open format for multi-step workflows. Add `SKILL.md` files to `.ona/skills/` and the agent discovers and uses them when relevant.
[Learn more about skills](/docs/ona/agents-md#skills-for-repository-specific-workflows)
## TODO grouping in sessions
Ona Agent sessions now group TODO items together, making it easier to follow the agent's progress on multi-step tasks.
**What's new:**
* **Grouped display**: TODOs created together appear in a single collapsible container
* **Progress tracking**: See at a glance how many tasks are completed (e.g., "3/5")
* **Status indicators**: Each TODO shows its current state—pending, in progress, or done
* **Expandable details**: Click any TODO to see the work performed under it
* **Live updates**: Watch the agent's progress in real-time as it works through each item
## Security Agents now generally available
Security Agents configuration is now available to all organizations in **Settings > Policies**, allowing you to enable CrowdStrike Falcon protection for your workspaces.
## CLI improvements
The CLI continues to add new commands and quality-of-life improvements.
**New commands:**
* `gitpod environment keep-alive` — Prevent automatic shutdown during long-running tasks by watching a process or PID
* `gitpod logout` — Sign out of the CLI
* `gitpod network-troubleshoot` — Diagnose connectivity issues
* `gitpod user dotfiles` — Manage your dotfiles configuration
**SSH improvements:**
* Running `gitpod env ssh` without specifying an environment now shows an interactive picker
* Stopped environments automatically start when you connect via SSH
**New flags:**
* `--param key=value` for `ai automation start` — Pass parameters to automations
* `--phase` for `environment list` — Filter by phase (running, stopped, etc.)
* `--name` for `environment create` — Set a custom environment name
## Recommended editors
Projects can now configure recommended editors in project settings. Users will see these as recommended options when opening environments, and this also determines which JetBrains IDEs are warmed up during prebuilds.
## Before-snapshot automations
Automations now support a `before_snapshot` trigger type. Use this to run cleanup tasks, update dependencies, or perform other operations automatically before an environment snapshot is created.
## Other improvements
* Markdown files now show a rendered preview in the diff viewer.
* Snapshot progress displays completion percentage during snapshotting.
* "Ask Ona" button appears on devcontainer build failures for quick troubleshooting.
* New split button for selecting editor versions.
* New modal for upgrading AWS EC2 runners.
* New account settings modal for managing personal settings.
* Prompt input, contexts, and environment class persist across sessions.
* VS Code Browser and agents are now exempt from port sharing policy by default.
* Audit logs now include login and logout events (Enterprise).
* Email invites show pending status and warn before navigating away with unsent invites.
* Ona Agent no longer returns 502 errors with Claude Opus 4.5 or Sonnet 4.5 when provider fallback is enabled.
* Ona SWE no longer fails when Anthropic environment variables are set in your workspace.
* SCP file transfers no longer fail over slow networks.
* Hosted compute now allows exposing ports 1024-2999 (previously only 3000+).
## Prebuilds now available on GCP
Prebuilds are now supported on GCP Enterprise runners. Teams running Ona on Google Cloud infrastructure can now use prebuilds to reduce environment startup times.
**Requirements:**
* [Update your Terraform stack](/docs/ona/runners/gcp/update-runner#updating-infrastructure) to the latest version to enable snapshot permissions
**Getting started:**
* [Learn about prebuilds](/docs/ona/projects/prebuilds)
* [Set up prebuilds](/docs/ona/projects/prebuilds-setup)
## Ona now integrates with Linear
Ona agents can now connect with Linear to manage your project tasks directly from your development environment.
**What you can do:**
* **Create and manage issues**: Ask agents to create Linear issues from code, errors, or sessions
* **Search and filter**: Find issues by status, assignee, labels, or content
* **Update metadata**: Add comments, change status, update labels, and assign issues
* **Access project context**: Retrieve project information to inform development decisions
**How it works:**
1. **Organization setup**: Admins enable integrations at the organization level
2. **User authentication**: Individual users authenticate to grant agents access to their accounts
3. **Natural interaction**: Simply ask your agent to perform actions—no special commands needed
**Example interactions:**
* "Create a Linear issue for this bug with steps to reproduce"
* "Show me all high-priority issues assigned to me"
* "Update issue ABC-123 to mark it as in progress"
**Get started:**
* [Read the integrations documentation](/docs/ona/integrations/overview)
* [Learn about Ona Agents](/docs/ona/agents/overview)
## Custom domains for secure management plane access
Enterprise customers can now access the Ona management plane through their own custom domain with full TLS termination. This enables organizations to route all traffic through their controlled infrastructure, meeting strict security and compliance requirements.
**Why this matters:**
* **Security control**: All traffic to the management plane flows through infrastructure you own and manage
* **Compliance ready**: Meet organizational requirements for domain ownership and traffic routing
* **SSO integration**: Works seamlessly with your existing Single Sign-On configuration
* **Enforcement options**: Optionally block access via the default domain, ensuring all users go through your custom domain
**Supported cloud providers:**
* **AWS**: Uses VPC Endpoints and Network Load Balancer for private connectivity
* **GCP**: Uses Private Service Connect (PSC) and regional HTTPS Load Balancer with support for both internal (private) and external (public) load balancer configurations
**How it works:**
1. Register your custom domain in the Ona dashboard with your cloud provider details
2. Deploy the required infrastructure in your AWS or GCP account
3. Configure DNS to point your domain to the load balancer
4. Optionally enforce custom domain access for all users
**Getting started:**
* Review the [Custom domain documentation](/docs/ona/custom-domain) for setup instructions
* For GCP deployments, [contact Ona](https://ona.com/contact/sales) to get access to the Terraform module
This feature is available exclusively to Enterprise customers.
## Enterprise Runner now available in AWS Paris (`eu-west-3`) region
The Ona Enterprise Runner is now available in the AWS Paris (`eu-west-3`) region, expanding deployment options for teams requiring data residency in Western Europe.
**Why this matters:**
* **Regional compliance**: Meet data residency requirements for France and the EU
* **Lower latency**: Improved performance for teams based in Western Europe
* **Enterprise ready**: Full Enterprise Runner capabilities including AI agent integration and direct connectivity
* **Flexible deployment**: Deploy in your VPC with custom networking configurations
**Getting started:**
* [Contact sales](https://ona.com/contact/sales) to enable Enterprise Runner
* Follow the [AWS Enterprise Runner setup](/docs/ona/runners/aws/enterprise-runner/setup) guide
* Configure your runner to use the eu-west-3 region
This expansion is available exclusively to Enterprise customers.
## Extended Single Sign-On (SSO) support
We've significantly expanded our SSO capabilities to support more complex organizational structures and authentication requirements.
**What's new:**
* **Multiple email domains per login provider**: Configure several email domains for a single identity provider, ideal for organizations with multiple subsidiaries or acquired companies
* **Multiple identity providers per organization**: Set up more than one identity provider (e.g., both Okta and Azure AD) to accommodate different teams or authentication requirements
* **Cross-organization domain support**: Use the same email domain across different organizations—users are presented with a list of login options to select their organization
**Why this matters:**
* **Enterprise flexibility**: Large organizations with complex structures can now centralize authentication across all their domains
* **M\&A ready**: Easily onboard acquired companies without forcing immediate identity provider migrations
* **Multi-team support**: Accommodate different authentication requirements for employees, contractors, and partners within the same organization
**Getting started:**
* Navigate to [Settings → Organization → SSO](https://app.ona.com/settings/sso)
* Add additional email domains to existing login providers or configure new identity providers
* Learn more in our [SSO documentation](/docs/ona/sso/overview)
This feature is available exclusively to Enterprise customers.
## Run prebuilds as service accounts
Prebuilds can now run as [service accounts](/docs/ona/organizations/service-accounts), decoupling prebuild execution from individual user accounts. This ensures prebuilds continue working regardless of user availability or permission changes.
**What's new:**
* Configure the prebuild executor in project settings
* Choose between a user (default) or a service account
**Why this matters:**
* Prebuilds no longer break when team members leave or change roles
* Dedicated credentials for prebuild execution
**Getting started:**
* [Learn about prebuild executors](/docs/ona/projects/prebuilds#prebuild-executor)
* [Configure the executor](/docs/ona/projects/prebuilds-setup#4-configure-the-executor)
* [Set up service accounts](/docs/ona/organizations/service-accounts)
This feature is available exclusively to Enterprise customers.
## Automation logs in prebuilds
Prebuild logs now include output from automation tasks, making it easier to debug prebuild failures and understand what ran during prebuild execution.
See [Viewing Logs](/docs/ona/projects/prebuilds-management#viewing-logs) for details.
## Editor version restrictions for organization policies
Organization administrators can now restrict which versions of editors their team can use, in addition to controlling which editors are available. This provides greater control over development environment consistency and security.
**Why this matters:**
* **Stability**: Standardize on tested versions before adopting the newest releases
* **Security**: Control version updates to verify security patches before organization-wide deployment
* **Compatibility**: Ensure all team members use versions tested with your workflows and integrations
**How it works:**
* Configure version restrictions in the same "Manage Editors" dialog as editor restrictions
* Currently available for JetBrains IDEs (IntelliJ IDEA, PyCharm, GoLand, etc.)
* Users attempting to use non-allowed versions automatically fall back to the latest allowed version
**Getting started:**
* Navigate to [Settings → Organization → Policies](https://app.ona.com/settings/policies)
* Click "Manage Editors" and select the specific versions you want to allow
* Learn more in our [Organization Policies documentation](/docs/ona/organizations/policies#editor-restrictions)
## Prebuilds: Faster environment startup times
Prebuilds reduce environment startup times by pre-executing your Dev Container build, lifecycle commands, and automation tasks. When you create an environment from a project with prebuilds enabled, it starts from a snapshot instead of running the full setup process.
**How it works:**
* Configure prebuilds at the project level with a daily schedule
* Prebuilds run your Dev Container build, `onCreateCommand`, `updateContentCommand`, and automation tasks with the `prebuild` trigger
* A snapshot is created and used for all new environments from that project
* Prebuilds are automatically deleted after 7 days
**Availability:**
* AWS Enterprise runners
* GCP Enterprise runners
* Ona Cloud
**Pricing:**
* **Ona Cloud**: Environment usage is billed normally during prebuild creation. Snapshot storage is currently free (pricing may be introduced in the future).
* **Enterprise**: You pay for compute resources during prebuild creation and storage costs for the snapshot. Storage is billed only for actual data stored (e.g., 50GB used on a 100GB volume = 50GB billed).
**Getting started:**
* [Learn about prebuilds](/docs/ona/projects/prebuilds)
* [Set up prebuilds](/docs/ona/projects/prebuilds-setup)
* [Manage prebuilds](/docs/ona/projects/prebuilds-management)
## Ona Agents now available on GCP Runner
Ona Agents are now fully supported on GCP Runner, bringing AI-powered development assistance to your Google Cloud infrastructure. Teams using GCP Runner can now leverage Ona Agents to accelerate development with up to 4x productivity gains—all while keeping code and data secure within your VPC.
**Why this matters:**
* **AI-powered development in your VPC**: Use Ona Agents with the same security and compliance benefits of GCP Runner
* **Flexible LLM options**: Configure Google Vertex AI or other supported LLM providers to power your agents
* **Enterprise-grade control**: Maintain full control over your AI infrastructure with your own LLM provider
* **Native integration**: Agents work with your GCP Runner environments
**Getting started:**
* [Contact sales](https://ona.com/contact/sales) or reach out to your account executive to enable GCP Runner with Ona Agents
* Review the [GCP Runner overview](/docs/ona/runners/gcp/overview) and [setup guide](/docs/ona/runners/gcp/setup)
* Learn about [Ona Agents](/docs/ona/agents/overview) and supported capabilities
* Configure your [LLM provider](/docs/ona/agents/llm-providers/overview) (Google Vertex AI recommended for GCP)
This feature is available exclusively to Enterprise customers.
## Organize teams and control access with Groups
Ona now supports Groups, giving you fine-grained control over who can access projects and runners in your organization. Organize teams by function or infrastructure needs, add members, and share resources with them.
**Why this matters:**
* **Keep workspaces focused**: Developers see projects relevant to their work, not everything
* **Share smarter**: Give the right access without making everyone an admin
* **Support compliance**: Route EU developers to EU runners, ML engineers to GPU infrastructure
**How it works:**
* Create groups in **Settings → Members → Groups**
* Share projects and runners with specific groups using the Share dialog
* Assign role-based permissions: User (view/use), Editor (manage), or Admin (full control)
* Built-in warnings prevent access issues when projects and runners aren't aligned
Learn more in our [Groups documentation](/docs/ona/organizations/groups) and [Resource Sharing guide](/docs/ona/organizations/sharing-resources).
## Enterprise Runner now available in AWS Mumbai (`ap-south-1`) region
The Ona Enterprise Runner is now available in the AWS Mumbai (`ap-south-1`) region, expanding deployment options for teams requiring data residency in South Asia.
**Why this matters:**
* **Regional compliance**: Meet data residency requirements for India and South Asia
* **Lower latency**: Improved performance for teams based in the region
* **Enterprise ready**: Full Enterprise Runner capabilities including AI agent integration and direct connectivity
* **Flexible deployment**: Deploy in your VPC with custom networking configurations
**Getting started:**
* [Contact sales](https://ona.com/contact/sales) to enable Enterprise Runner
* Follow the [AWS Enterprise Runner setup](/docs/ona/runners/aws/enterprise-runner/setup) guide
* Configure your runner to use the ap-south-1 region
This expansion is available exclusively to Enterprise customers.
## Ona is now Available in Google Cloud.
We’re expanding where great software gets built. From today, Ona can also run natively in Google Cloud, in your VPC.
If your company bet on GCP for scale, security, and data residency, you can now bring Ona right to your VPC. Your code stays in your infrastructure. Your controls stay yours. The developer experience gets dramatically better.
**Why this matters:**
* **Get started in minutes**: a Terraform apply stands up everything you need.
* Keep traffic where you want it: external or internal HTTPS load balancing.
* **Use your standards**: CMEK, proxy, custom images, labels, enterprise IAM.
* **Ship faster**: native access to private GAR images, observability out of the box.
* **Agent Ready**: Google Cloud is Ona Agents ready. Learn how to use [Ona Agents](/docs/ona/agents/overview) and join our customers in getting up to 4x more productivity.
Google Cloud is available exclusively to Enterprise customers.
**Get started:**
* [Contact sales](https://ona.com/contact/sales) to enable Enterprise
* Follow the [GCP Runner setup](/docs/ona/runners/gcp/setup) and read the [Overview](/docs/ona/runners/gcp/overview)
## View and Review Code changes directly from mobile
You can now view all code changes made in an environment on mobile
in a dedicated "Code changes" page.
* The "Changes" tab shows you a list of changed files in the environment. You can expand each file to view the diff of the file.
* The "Files" tab gives you a tree view of all the changed files, which you can use to navigate to the diff of the file you want.
To open the page, go to the "Git status" panel in "Environment details" page, click on any changed file, and you will be taken to the corresponding file diff.
## Visualize architecture and workflows with Mermaid diagrams
Ona Agent can now generate and render Mermaid diagrams directly in sessions, making it easy to visualize system architecture, dependencies, workflows, and data relationships without leaving your development environment.
**How to use:**
Simply ask Ona Agent to create diagrams using natural language:
* Draw an architecture diagram showing how our microservices communicate
* Create a sequence diagram for the authentication flow
* Generate an ER diagram for our database schema
Ona Agent will generate the appropriate Mermaid diagram, which you can preview, zoom, and copy directly in the session. The agent handles all the Mermaid syntax, so you can focus on describing what you want to visualize.
**Supported diagram types:**
* Flowcharts and decision trees
* Sequence diagrams
* Class diagrams
* Entity-relationship diagrams
* State diagrams
* Gantt charts
* Git graphs
Learn more in our [Mermaid diagrams documentation](/docs/ona/agents/mermaid-diagrams).
## Claude Sonnet 4.5 now available
Claude Sonnet 4.5 is now available in Ona, bringing enhanced reasoning capabilities and improved code generation to your development workflow.
**How to enable Sonnet 4.5:**
* **Free and Core tiers**: Sonnet 4.5 is automatically available, no setup or changes are required
* **Enterprise tier**: Organization admins can [configure your LLM provider](/docs/ona/agents/llm-providers/overview) by selecting Sonnet 4.5 in the settings for each runner. Ensure you are on [the latest runner version runner](https://ona.com/docs/ona/runners/aws/update-runner) to update. Removing a previous LLM integration on a runner will break existing sessions.
**Learn more:**
* [LLM Providers Overview](/docs/ona/agents/llm-providers/overview)
* [Anthropic Configuration](/docs/ona/agents/llm-providers/anthropic)
* [AWS Bedrock Configuration](/docs/ona/agents/llm-providers/bedrock)
* [Google Vertex AI Configuration](/docs/ona/agents/llm-providers/google-vertex)
* [Updating AWS Runner](https://ona.com/docs/ona/runners/aws/update-runner)
## Encode your expertise into slash commands
Encode your team's best practices into reusable slash commands that work across your entire organization in Ona. Useful for automating standards such as PR or commits patterns and for turning complex workflows into simple and consistent actions.
* Ensure everyone follows the same PR format or review process
* Capture your best reviewer's approach in commands like `/review-like-sarah`
* Automate common tasks like `/pr`, `/fix-ci-build`, or `/weekly-digest`
Every command runs in a fully-configured Ona environment with all of your dependencies, authentication, and secrets set up. So `/test` can run against real databases and integrations and `/fix-ci-build` has everything it needs to succeed. All environments are isolated so there's never the risk of breaking your laptop or your flow.
For more, see the [skills docs](/docs/ona/skills) and our [best practices guide](/docs/ona/best-practices).
## Track agent progress with todos
As agents become more autonomous and handle longer workflows, you need a way to monitor progress without watching every detail. That's why before starting to work Ona Agents create and manage their own todo lists.
* See the plan at a glance instead of reading through detailed agent output
* Quickly spot when an agent might need steering without monitoring every action
* Add, remove, or modify todos mid-task to adjust your agent's approach
With todos you can check in to see the big picture, and intervene only when needed. With each agent maintaining its own todo list, you can start to orchestrate your own fleet of agents without losing track of who's doing what.
See our [best practices guide](/docs/ona/best-practices) for more.
## Ona now supports AGENTS.md
Ona now supports AGENTS.md, the emerging open standard for guiding AI coding agents used by thousands of open-source projects and supported by tools like OpenAI and Google.
AGENTS.md provides a consistent way to communicate project conventions to your coding agent. Add to the file any project-specific commands, coding standards, and architecture guidance that will help your agent write code that fits your team's patterns. If you already use AGENTS.md with another agentic tool, Ona automatically loads it into every environment.
See the [agents.md documentation](/docs/ona/agents-md) for more.
## Keep momentum on any device from mobile to iPad
Capture ideas the moment inspiration strikes. Whether you're waiting for coffee or commuting home, Ona gives you the full power of development environments from any device without any tunnels or complex setups. So ideas can become reality, wherever you are.
## Privacy-first coding agent inference with Bedrock and Vertex
Ona Enterprise supports LLM inference via Amazon Bedrock, Google Vertex and Anthropic giving you secure control over your AI inference from within your private VPC. Your code, prompts, and AI interactions never leave your network. Meet strict regulatory needs with inference that runs entirely within your security perimeter. Combined with Ona's existing VPC deployment this creates an end-to-end secure development environment platform.
This feature is available today for all Ona Enterprise customers.
Learn more about [Ona Enterprise](https://ona.com/enterprise).
## Sandboxed AI software development with Dev Container
Unlike AI coding tools that run on shared infrastructure or on developer machines, Ona provides true sandboxing for writing software with agents. Agents can't access each other's work or leak secrets between projects. Ona Agents execute within isolated environments defined by Dev Container.
* **Complete agent isolation**: Each agent runs in its own Dev Container with OS level isolation, preventing cross-contamination between source control and projects.
* **Ephemeral by design**: Environments are created newly for each task (e.g. issue, bug, feature) and destroyed on completion, ensuring no persistent attack surface.
* **Standardized environments**: Dev Containers are defined in code and pre-configured with your exact dependencies and access credentials.
If you're already using the Dev Container specification, Ona will automatically use your existing devcontainer.json. For new projects, Ona can help generate appropriate Dev Container configurations based on your codebase. Available for all Ona pricing tiers.
Learn more about [Ona Dev Container support](/docs/ona/configuration/devcontainer/overview).
## Standardized JetBrains plugin management via devcontainer.json
You can now configure JetBrains IDE plugins directly in your devcontainer.json file, enabling fully standardized plugin management across development environments.
This update lets teams pre-install essential plugins from the JetBrains Marketplace using their plugin IDs, ensuring consistent tooling for all team members. It eliminates the need for manual plugin installation, reducing setup time and improving onboarding speed.
**Key capabilities:**
* **Plugin installation**: Specify plugin IDs from the JetBrains Marketplace for automatic installation.
* **Team consistency**: Guarantee the same set of plugins across every developer environment.
* **Faster onboarding**: Remove the manual step of plugin setup for new contributors.
**Example configuration:**
```json title="devcontainer.json" theme={null}
{
"name": "My Project",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"customizations": {
"jetbrains": {
"plugins": ["org.intellij.plugins.hcl", "com.intellij.kubernetes"]
}
}
}
```
This enhancement removes the previous limitation of non-customizable JetBrains plugin setups, bringing a consistent, repeatable configuration to the entire Dev Container ecosystem.
See the [JetBrains documentation](/docs/ona/editors/jetbrains) to learn more.
## HTTPS support for environment services via port sharing
You can now expose environment services over HTTPS using Gitpod's port sharing feature. This enables secure communication with applications running in your environment, which is ideal for testing HTTPS-only setups or integrating with services requiring encrypted transport.
**What's new:**
* **UI integration**: Select https as the protocol in the port sharing dialog
* **CLI support**: Use `--protocol https` with `gitpod environment port open` to expose environment service ports securely.
**Use cases:**
* Applications with HTTPS-only redirects or policies
* Streaming APIs requiring secure connections
See [port sharing documentation](/docs/ona/integrations/ports) for setup instructions.
## Support for multiple region-aware environment classes per project
We're excited to announce that Gitpod now supports Multiple environment classes for a project, a highly requested feature that enhances reliability and flexibility for organizations.
With this new feature, you can:
* Configure up to 30 environment classes per project, providing built-in regional redundancy
* Set a default environment class while offering alternatives for user selection
* Avoid creating multiple projects for the same repository across different regions
* Benefit from automatic fallback options when a preferred environment class is unavailable
**Highlights:**
* **Enhanced Resilience**: Eliminate single points of failure with multiple region support in a single project
* **User Flexibility**: Users can select their preferred environment class through an intuitive UI
* **Intelligent Fallback**: When a selected environment class is unavailable, users receive informative error messages and alternative options
* **Preference Persistence**: The system remembers user preferences for future project launches
* **Simplified Project Management**: Reduce project proliferation by consolidating multi-region support
Learn how to configure multiple environment classes for a project in our [documentation](/docs/ona/projects/overview).
## Archive & Auto-delete for Environments
We're excited to announce Archive & Auto-delete, a new feature that automatically manages your environment lifecycle to help reduce storage costs.
With this new feature, you can:
* Automatically archive inactive environments after 7 days of inactivity
* Configure auto-deletion policies to remove archived environments after 1, 2, or 4 weeks
* Set organization-wide retention limits to ensure consistent storage management
**Highlights:**
* **Two-stage lifecycle**: Environments are archived first (reversible), then auto-deleted based on your preferences
* **Flexible policies**: Users can set preferences within organization-defined limits
* **Bulk management**: Delete all archived environments at once with safety controls
* **Visual indicators**: Archive badge shows when you have archived environments
This feature helps reduce storage costs while maintaining control over environment retention. Organization-wide auto-delete policies are available for Enterprise customers.
Learn how to configure Archive & Auto-delete in our [documentation](/docs/ona/environments/archive-auto-delete).
## Organization Secrets support
We're excited to announce that Gitpod now supports Organization secrets, alongside existing User and Project secrets.
With this new feature, you can:
* Configure organization-wide secrets for all Environments in the organization
* Ensure consistent access to shared credentials and API keys for all team members
**Highlights:**
* **Files**: Secrets can be mounted as files for complex structures e.g. JSON.
* **Environment Variables**: Inject secrets as environment variables.
**What's the benefit of files?** Files offer better security by avoiding issues like process visibility, crash logging leaks, and unintentional inheritance by child processes.
Learn how to configure organization secrets in our [documentation](/docs/ona/organizations/organization-secrets).
## VPC endpoint support for Enterprise AWS runners
Enterprise AWS runners now support VPC endpoints, allowing you to connect to Gitpod's management plane using AWS PrivateLink.
This enhancement provides:
* **Increased security** - All traffic between your runner and Gitpod stays within AWS's network backbone
* **More reliable connectivity** - Eliminates dependency on internet routing and potential connectivity issues
* **Compliance ready** - Ideal for customers with strict security requirements that prohibit internet-bound traffic
**How it works:**
With VPC endpoints enabled, your Enterprise AWS runner connects to Gitpod's management plane through AWS PrivateLink:
* **DNS resolution** - app.gitpod.io automatically resolves to VPC endpoint IP addresses within your VPC
* **AWS PrivateLink** - Traffic flows through Amazon's network infrastructure via VPC endpoints
* **No runner changes** - No changes required to your existing runner configuration
**Getting started:**
To enable VPC endpoints for your Enterprise AWS runner:
1. Create an Interface VPC Endpoint in your AWS account pointing to Gitpod's service
2. Configure the endpoint in the same VPC where your runner is deployed
3. Enable DNS names for automatic resolution
The runner dashboard will automatically detect and display "via VPC endpoint" as the connection type once configured.
Learn more about setting up VPC endpoints in our [Enterprise runner setup documentation](/docs/ona/runners/aws/enterprise-runner/setup).
**Availability:** This feature is available to Enterprise customers using AWS runners.
## Enterprise AWS runner with AI agent and direct connectivity
Enterprise AWS Runners are now available for Enterprise customers, providing additional capabilities beyond our AWS Runners.
**Key features:**
* **Ona AI Agent Integration**: AI-powered assistance for automatic Dev Container generation and environment setup
* **Direct Connectivity**: Bypass Gitpod's central gateway using your own Network Load Balancer with custom domain and SSL/TLS certificate
* **Advanced Networking**: Custom VPC configurations with flexible subnet architecture for internal-only or internet-facing deployments
* **Flexible Deployment**: Deploy behind corporate firewalls with future HTTP proxy support
**Availability:**
Enterprise AWS Runners are exclusively available to Enterprise customers. If you're on the Enterprise tier, contact your Gitpod account manager to get started.
**Coming soon:**
We're continuing to enhance the Enterprise Runner with additional enterprise-focused features:
* **HTTP Proxy Support**: Custom HTTP proxy configuration for environments behind corporate firewalls
* **Custom CA Certificate Support**: Integration with enterprise certificate authorities and custom certificate chains
Learn more about setting up your Enterprise AWS Runner in our [documentation](/docs/ona/runners/aws/enterprise-runner/overview).
## Introducing our AI powered Development Environment setup workflow
Ona's Enterprise SWE agent, Ona agent, now automatically analyzes repositories and generates Dev Container and automations configurations, helping you discover the value of Gitpod much faster.
When developers open an environment without existing Dev Container configurations, Gitpod offers to run our AI powered workflow to generate the configuration automatically.
Ona works relentlessly, rebuilding and testing the generated configuration until it is confident it gives you a productive setup.
**How it works:**
1. Open an environment in Gitpod without an existing Dev Container configuration
2. Gitpod offers to run our Ona powered setup agent automatically
3. Ona generates devcontainer.json and automations.yaml based on detected dependencies and best practices
4. Review and commit configurations for your team
5. All subsequent environment launches use the optimized configuration
**Availability:**
This feature is available to our enterprise customers. [Contact sales](https://ona.com/contact/get-demo).
## Gitpod now supports Windsurf editor
Gitpod now supports Windsurf as an editor option for your development environments. Windsurf integrates advanced AI capabilities directly into your development workflow, enhancing productivity through natural language interaction and intelligent code assistance. Experience features like Tab-to-Import, real-time linting, and Cascade AI assistant to streamline your coding process.
**Using Windsurf with Gitpod:**
To get started with Windsurf in Gitpod, simply select Windsurf from the editor selector dropdown by clicking on the dropdown arrow next to the editor button on the action bar.
Check our [documentation](/docs/ona/editors/windsurf) for more details on how to use Windsurf with Gitpod.
## Faster development environment start times for AWS with Dev Container build caching
Development environment starts are now faster for organizations using AWS Runners with the addition of a new Dev Container build cache Runner setting that uses Amazon ECR.
With this setting enabled you get:
* Faster startup times from minutes to seconds for environments with identical Dev Container configurations
* Reclaimed developer time: Convert 5 minute development environment startup delays into 30-second starts
* Automatically optimized start times performance without any configuration changes required
**How does it work?**
With the setting enabled on your AWS runner, the first environment created from a project will cache the built Dev Container image. Any changes to the Dev Container configuration will trigger a new cache build on the next environment creation.
* All subsequent starts using the same project will benefit from significantly faster startup times.
* Images are cached for 30 days before automatically expiring to manage storage costs.
* The cache is restricted to users of the project and can be disabled in runner settings if needed.
The build cache speeds up developers workflows and incentivizes developers to use secure short-lived development environments.
**Getting started:**
For new AWS runners: The Dev Container image cache is enabled by default.
For existing AWS runners:
1. Update your CloudFormation stack to the latest version that supports the cache
2. Go to Settings → Runners in your Gitpod organization
3. Select your AWS runner and toggle Dev Container image cache to enabled
**Note:** Upgrading CloudFormation templates from January 2025 or earlier will cause existing environments to become inaccessible due to SSH port changes. Before upgrading, either stop existing environments or manually update the security group after the upgrade.
Learn more about configuration, security considerations, and troubleshooting in our [Dev Container image cache documentation](/docs/ona/runners/devcontainer-image-cache).
## Analyze your organization's Gitpod usage with Insights
We're excited to announce the launch of Gitpod Insights, an analytics dashboard that helps Enterprise organizations understand and optimize their Gitpod usage and cloud cost.
With Gitpod Insights, you can:
* **Analyze environment usage** across your entire organization
* **Optimize cloud costs** by identifying opportunities to right-size resources
* **Monitor adoption** by tracking active users and environment metrics
The Insights dashboard provides key metrics, including:
* **Active Users**: Track weekly active users and engagement patterns
* **Environment Usage**: Monitor total environments and runtime hours
* **Resource Distribution**: View usage by projects, users, and environment classes
Organization administrators can access Insights directly from the Gitpod dashboard by selecting "Insights" from the left navigation menu. The dashboard offers flexible time range options from daily to yearly views, with automatically adjusted data granularity for optimal analysis.
Learn more about Gitpod Insights in our [documentation](/docs/ona/organizations/insights).
## Create development environments from scratch without a Git repository
You can now create development environments from scratch directly from the environment creation modal. This new option allows you to:
* Start with a clean slate using your organization's default environment image
* Start an environment without requiring a git provider configured on a runner
* Begin development immediately without needing to clone an existing repository
To create a blank environment:
1. Click the `Create Environment` button
2. Select `Create Environment From Scratch`
3. Choose your preferred environment class
4. Click `Create` to start your new environment
See [default environment image documentation](/docs/ona/organizations/policies/default-image) for details.
## Organization policies to manage cost, security and developer experience
Organization policies are now available on our Enterprise plan for organizations, giving administrators centralized controls to manage security, developer experience, and resource costs.
With Organization policies, you can:
* **Enhance security** - Restrict development environments to only run in the cloud (e.g. not locally) and control which editors developers can use to access your code
* **Standardize experience** - Create a consistent "golden path" by defining allowed editors and default container images
* **Control costs** - Set auto-stop timeout limits and maximum environment counts to prevent unexpected resource usage
* **Enforce governance** - Require environments to be created only from approved projects
* **Manage resources** - Limit concurrent running environments per user for optimized resource allocation
Discover how to configure Organization Policies in our [documentation](/docs/ona/organizations/policies).
## Gitpod now supports VS Code in the Browser
Gitpod now supports VS Code in the browser as well as regular desktop IDEs and editors. Giving developers access to secure development environments without installing any local tools, cloning any source code or managing any dependencies. Development environments that are fully automated and standardized.
With Gitpod and VS Code in the Browser, you can:
* Drive down your developer onboarding times by eliminating all manual setup for your development teams.
* Help developers review code easily by launching new development environments running in their browser tab.
* Drive down incident response times with SREs able to do on-the-go incident response direct from their mobiles.
* For secure enterprises, Gitpod [paired with a secure browser (like Island)](https://www.gitpod.io/blog/replace-vdi-with-gitpod-and-island) is a secure and performant alternative to traditional [VDI](https://www.gitpod.io/solutions/vdi).
### Getting started
To get started, simply click the "Open in VS Code in the Browser" button when starting a Gitpod environment. Check our [documentation](/docs/ona/editors/vscode-browser) for more details on features and capabilities.
## Gitpod now supports JetBrains Toolbox App
The JetBrains Toolbox App, a desktop application that helps you manage JetBrains IDEs and projects, now supports remote development in Gitpod environments.
This means you can:
* Use the familiar Toolbox App interface to manage your IDEs in Gitpod
* Connect to Gitpod environments from your desktop
* Install and update JetBrains IDEs in your remote environment
To get started, install the latest JetBrains Toolbox App (2.6+) and connect it to your Gitpod environments. Check our [documentation](/docs/ona/editors/jetbrains) for setup instructions.
Learn more about the JetBrains Toolbox App 2.6 release in the [official announcement](https://blog.jetbrains.com/toolbox-app/2025/04/toolbox-app-2-6-is-here-with-remote-development-support).
## User Secrets support
We're excited to announce that Gitpod now supports User secrets, alongside existing Project secrets.
With this new feature, you can:
* **Configure personal secrets** for all of your Environments
* **Integrate against 3rd party systems which use Personal Access Tokens** to authenticate seamlessly, and even use [atuin](https://atuin.sh/) to have persistent terminal history in your Environments.
Highlights:
* **Files**: Secrets can be mounted as files for complex structures e.g. JSON.
* **Environment Variables**: Inject secrets as environment variables.
**What's the benefit of files?** Files offer better security by avoiding issues like process visibility, crash logging leaks, and unintentional inheritance by child processes.
Learn how to configure your personal secrets in [our documentation](/docs/ona/configuration/secrets/user-secrets).
## AWS ECR private registry support
We're excited to announce that Gitpod now supports AWS ECR private registries with IAM-based authentication when using AWS EC2 runners.
With this new feature, you can:
* **Securely access private ECR repositories** without manually managing credentials
* **Simplify authentication workflows** using EC2 runner's IAM role
* **Seamlessly work with private container images** in your development environment
This native integration works automatically when:
* You're using AWS EC2 runners for your environments
* Your ECR registry and EC2 runners are in the same AWS account (or have appropriate cross-account access)
Setting up ECR registry access is straightforward through the Project Secrets interface. Simply select Container Registry Basic Auth, enter your ECR registry hostname, and the system will automatically configure runner-native authentication.
Learn how to configure IAM permissions and set up your ECR registry in our [documentation](/docs/ona/configuration/secrets/container-registry-secret#using-aws-ecr-with-iam-authentication).
## Domain Verification for SSO
Domain Verification is now available, allowing organization admins to verify ownership of their email domains through DNS TXT records. This feature strengthens security by confirming domain ownership before enabling SSO functionality. This ensures that only authorized users can access your organization using the specified domain.
Learn how to verify your domain from our [documentation](/docs/ona/sso/overview#step-1-verify-your-domain).
## Private container registry support
We're excited to announce that Gitpod now supports Container Registry Secrets, allowing you to securely authenticate with private container registries.
With Container Registry Secrets, you can now:
* Pull Dev Container images from private registries
* Authenticate with container registries during your development workflow
* Work with private images in your Flex environment without exposing credentials
This feature supports all major container registries using basic authentication, including:
* Docker Hub
* GitHub Container Registry
* GitLab Container Registry
* Azure Container Registry
Setting up Container Registry Secrets is straightforward through the Project Secrets interface. You'll need to provide the registry hostname, username, and password/token to create the authentication secret.
Learn how to set up and use Container Registry Secrets in our [documentation](/docs/ona/configuration/secrets/container-registry-secret).
**Note:** This initial release supports basic authentication only. Support for AWS ECR and other authentication methods will be coming in future updates.
## Dotfiles Support for Gitpod
Gitpod now supports dotfiles. Dotfiles are a way to customize your developer environment according to your personal needs.
Just configure what dotfiles repository to use and Gitpod will clone and install the dotfiles in every environment, ensuring everything is just the way you like it.
Head over to the [documentation](/docs/ona/configuration/dotfiles/overview) to learn how to get started.
## Introducing Gitpod SSO
We're excited to announce that Gitpod now supports Single Sign-On (SSO), making it easier than ever to manage access for your team. With SSO, your team can log in using their existing accounts with trusted Identity Providers like Okta, Azure AD, or Google using OpenID Connect (OIDC) integration.
This feature simplifies authentication by eliminating the need for separate credentials, enhances security by centralizing user management, and streamlines access across your organization. As an admin, you can easily set up SSO in your organization's settings using your IdP credentials and manage access with just a few clicks.
Learn how to set up SSO in our [documentation](/docs/ona/sso/overview).
## Introducing Gitpod secrets & environment variables
Gitpod now supports secrets and environment variables. Securely store and inject sensitive data such as API keys and access credentials into your development environment. Secrets are encrypted using AES256-GCM and stored securely. Only environments launched from an associated project can access it's secrets.
Highlights:
* **Environment Variables**: Inject secrets as environment variables.
* **Files**: Secrets can be mounted as files for complex structures e.g. JSON.
**What's the benefit of files?** Files offer better security by avoiding issues like process visibility, crash logging leaks, and unintentional inheritance by child processes.
See [secrets docs](/docs/ona/configuration/secrets/overview) for more.
## Migrate from .gitpod.yml to devcontainer.json
We recently announced that Ona now supports Dev Container. To help ease your migration you can run the following command directly from a Ona environment:
```sh theme={null}
gitpod env migrate
```
# Add your first secret
Source: https://ona.com/docs/ona/add-first-secret
Store API keys and credentials so agents can connect to external services.
Agents need credentials to connect to external services - Linear for issue tracking, AWS for cloud resources, API keys for MCP servers. Secrets store these credentials securely and inject them into your environments automatically.
## What you'll do
Add a secret that your environments and agents can use. We'll use a Linear API key as an example, but the process is the same for any credential.
## Choose a scope
Secrets can be configured at three levels:
| Scope | Best for |
| ---------------- | ------------------------------------------------------------------------------- |
| **User** | Personal API keys (Linear, GitHub tokens). Only available in your environments. |
| **Project** | Shared credentials for a specific repository. Available to all project members. |
| **Organization** | Company-wide credentials. Available across all projects. |
For personal API keys like Linear, use **User secrets**.
## Add a user secret
1. Go to **Settings** > **My Account** > **Secrets**
2. Click **New Secret**
3. Configure:
* **Secret type**: Environment variable
* **Name**: `LINEAR_API_KEY`
* **Secret**: Your Linear API key (from Linear Settings > API)
4. Click **Add**
The secret is now available as an environment variable in all your environments.
**Security tradeoff**: Environment variables can leak through process listings and logs. [File secrets](/docs/ona/configuration/secrets/files) are more secure, but many tools (including MCP servers) expect credentials as environment variables. For API keys that can be rotated, this tradeoff is often acceptable. For passwords and private keys, prefer file secrets.
## Import from a .env file
If you already have a `.env` file, you can import all its variables as secrets at once.
1. Go to **Settings** > **My Account** > **Secrets**
2. Click **Import .env**
3. Drag and drop your `.env` file, or click **browse** to select it
4. Review the parsed variables. Duplicates of existing secrets are flagged and skipped
5. Click **Import**
The file must use standard `KEY=VALUE` format, one variable per line. Comments and blank lines are ignored.
This works the same way on **Project** and **Organization** secret pages ([Enterprise plan](/docs/ona/organizations/organization-secrets) required for organization secrets).
## Verify it works
Start an environment and check the secret is injected:
```bash theme={null}
echo $LINEAR_API_KEY
```
You should see your key (or a masked version). Agents can now use this secret to connect to Linear.
## Common secrets for agents
| Secret | What it enables |
| ------------------- | -------------------------------------------- |
| `LINEAR_API_KEY` | Issue creation and management via Linear MCP |
| `GITHUB_TOKEN` | Enhanced GitHub access via GitHub MCP |
| `AWS_*` credentials | Cloud resource access |
To use your ChatGPT plan with Codex, connect [Codex](/docs/ona/integrations/configure-codex) in **User Settings > Integrations** instead of adding an API key as a secret.
## Secret precedence
If the same secret name exists at multiple levels, user secrets override project secrets, which override organization secrets. This lets you use personal credentials while teams share defaults.
## Next steps
* [Configure Linear](/docs/ona/integrations/configure-linear) to use your API key
* [Learn about MCP servers](/docs/ona/mcp) that use secrets
* [Secrets reference](/docs/ona/configuration/secrets/overview) for all secret types
# Teach agents your codebase
Source: https://ona.com/docs/ona/agents-md
Help agents understand your project conventions, commands, and architecture with AGENTS.md.
Every codebase has conventions — how you name branches, which commands run tests, where important files live. Without context, agents guess: they run `npm test` when your project uses `yarn test`, or put a component in the wrong directory. AGENTS.md teaches them your conventions, commands, and architecture so they produce code that fits your project.
[AGENTS.md](https://agents.md) is an open standard stewarded by the Linux Foundation, supported by Ona and other AI coding tools. Think of it as a README for agents — the tribal knowledge that senior engineers carry in their heads.
## Create your AGENTS.md
Create an `AGENTS.md` file in your repository root:
```markdown theme={null}
# Project Guidelines
## Commands
- `npm test` - Run tests
- `npm run build` - Build for production
- `npm run lint` - Check code style
## Project Structure
- `src/components/` - React components
- `src/utils/` - Helper functions
- `src/api/` - API client and types
## Code Style
- Use TypeScript for all new files
- Components use PascalCase (e.g., `UserProfile.tsx`)
- Utilities use camelCase (e.g., `formatDate.ts`)
```
Agents automatically load this file at the start of every session.
## Keep it concise
Shorter is better. As instruction count increases, instruction-following quality decreases. Aim for:
* **Under 300 lines** - the recommended maximum
* **Under 60 lines** - ideal for most projects
If you need more detail, link to other files rather than duplicating content:
```markdown theme={null}
## Code Style
Follow the guidelines in [CONTRIBUTING.md](./CONTRIBUTING.md)
```
## What to include
**Commands** - The most important section. Tell agents exactly how to:
* Run tests
* Build the project
* Start the dev server
* Lint and format code
**Project structure** - Where things live:
* Key directories and their purpose
* Where to add new components or features
**Conventions** - How your team does things:
* Branch naming patterns
* Commit message format
* Code style rules
**Security considerations** - What to avoid:
* Files that should never be committed
* Sensitive patterns to watch for
* Security-related commands to run
## Make critical rules stand out
Agents pay attention to emphasis. For rules that must not be broken:
```markdown theme={null}
**IMPORTANT**: Always run `npm run typecheck` before committing.
**ALWAYS** use the `useApi` hook for data fetching, never raw fetch calls.
**NEVER** commit .env files or API keys.
```
## Use nested files for large projects
For monorepos or large codebases, you can place AGENTS.md files in subdirectories. Agents read the nearest file in the directory tree, so each package can have tailored instructions:
```
repo/
├── AGENTS.md # Global conventions
├── packages/
│ ├── api/
│ │ └── AGENTS.md # API-specific instructions
│ └── web/
│ └── AGENTS.md # Frontend-specific instructions
```
## Example
```markdown theme={null}
# Project Guidelines
## Commands
- `npm test` - Run test suite (required before PR)
- `npm run build` - Production build
- `npm run dev` - Start dev server at localhost:3000
- `npm run typecheck` - TypeScript validation
**IMPORTANT**: Run `npm test` and `npm run typecheck` before creating a PR.
## Project Structure
- `src/components/` - Reusable UI components
- `src/features/` - Feature-specific code
- `src/lib/` - Shared utilities
## Conventions
- TypeScript for all files
- Components: PascalCase (`UserCard.tsx`)
- Branch naming: `initials/short-description`
## Security
**NEVER** commit `.env` files or hardcode API keys.
Run `npm run security-check` before merging to main.
```
After adding AGENTS.md, start a session and ask the agent to make a change. If it misses a convention, add emphasis or move that rule higher in the file.
## Skills for multi-step workflows
[Agent Skills](https://agentskills.io) are `SKILL.md` files that live in your repository. For repeatable, multi-step procedures (deployment workflows, triage runbooks, PR checklists), use [repository skills](/docs/ona/agents/skills). The agent discovers and loads them automatically when a task matches.
For organization-wide workflows that apply across all projects, use [organization skills](/docs/ona/skills).
## Getting notified when an agent finishes
Enable the completion sound in [Settings > Preferences](https://app.ona.com/settings/preferences) to hear when a task completes.
For webhook-style notifications, add an instruction to your `AGENTS.md` that tells the agent to run a `curl` command after completing all work:
```markdown theme={null}
After completing all tasks, run in the background:
curl -X POST -H "Content-Type: application/json" \
-d '{"status": "done"}' https://your-webhook-url.com/
```
You can also monitor task completion programmatically via the [WatchEvents API method](https://ona.com/docs/api-reference).
## Next steps
* [Create organization skills](/docs/ona/skills) for organization-wide workflows
* [Set up your first environment](/docs/ona/configuration/devcontainer/getting-started) so agents have a reliable run loop
* Learn more at [agents.md](https://agents.md)
# Codex Agent
Source: https://ona.com/docs/ona/agents/codex
Run the open-source Codex harness in Ona Cloud or on a supported customer-managed runner.
Available on the Core plan and higher. Codex Agent runs on Ona Cloud and supported customer-managed runners. [Contact sales](https://ona.com/contact/sales) to learn more.
Codex Agent runs the [open-source Codex harness](https://github.com/openai/codex) in an Ona environment with your project context, environment isolation, integrations, and guardrails.
## How Codex Agent works
Codex Agent can read your repository, use configured tools, run commands, and open pull requests while following your organization's policies.
On Ona Cloud, Codex Agent uses the model access available to your organization. Core users can connect their ChatGPT account so Codex model requests use their ChatGPT plan instead.
On a customer-managed runner, Codex Agent uses OpenAI model access provided by Ona Intelligence or an OpenAI-compatible LLM integration configured for that runner. See [Model access](/docs/ona/agents/llm-providers/overview) for the available options.
## Prerequisites
* Your organization is on a Core or Enterprise plan.
* Codex Agent is enabled for your organization.
* Customer-managed runners require OpenAI model access through Ona Intelligence or an OpenAI-compatible LLM integration.
Core users who want to use a ChatGPT plan for Codex model requests also need a ChatGPT account with Codex access. See [Connect Codex to ChatGPT](/docs/ona/integrations/configure-codex).
## Start Codex Agent
1. Start an environment.
2. Open the conversation menu.
3. Choose **Codex**.
4. Describe the task you want Codex Agent to work on.
## Organization controls
Administrators can control Codex Agent behavior for the organization.
### Goal mode
Goal mode lets members set Codex goals that keep running until achieved. It is **enabled** by default.
To change it, go to **Organization Settings** > **Agents** and toggle **Goal mode** in the Codex settings. When disabled, members can still run Codex Agent, but requests that ask it to run in goal mode are rejected.
## Usage and billing
Compute and model usage follow your organization's plan and model-access configuration:
* On Core, the environment consumes OCUs while Codex Agent runs. If you connect your ChatGPT account, OpenAI manages usage and limits for Codex model requests, and Ona does not charge OCUs for those model requests.
* On Enterprise, model usage follows the Ona Intelligence or BYOK configuration for your runner.
See [Cost & Budgets](/docs/ona/billing/usage) and [Model access](/docs/ona/agents/llm-providers/overview) for details.
## Related setup
* [Connect Codex to ChatGPT](/docs/ona/integrations/configure-codex): use your ChatGPT plan for Codex model requests
* [Model access](/docs/ona/agents/llm-providers/overview): configure model access for customer-managed runners
* [AGENTS.md](/docs/ona/agents-md): add project context for agents
* [MCP servers](/docs/ona/mcp): extend agent capabilities with external tools
# Image attachments
Source: https://ona.com/docs/ona/agents/image-attachments
Attach screenshots and images to agent prompts for visual context.
Attach PNG or JPEG images to your prompts so the agent can use them as context. This is useful for sharing error screenshots, UI mockups, design references, or terminal output.
**Example prompts with images:**
* "This button is misaligned, fix it" (with a screenshot of the UI)
* "Implement this design" (with a mockup attached)
* "Why is this test failing?" (with a screenshot of the error output)
## How to attach images
### Click the attach button
Click the paperclip icon in the prompt input bar, then select one or more image files from your file system.
### Drag and drop
Drag image files from your file system directly onto the prompt input area. A visual indicator appears when files are detected.
### Paste from clipboard
Copy an image or screenshot to your clipboard (e.g. with a screenshot tool), then paste it into the prompt input with **Cmd+V** (macOS) or **Ctrl+V** (Windows/Linux).
## Attached images in the prompt
After attaching, images appear as thumbnails above the prompt text. Click a thumbnail to preview it at full size. Click the **X** button on a thumbnail to remove it before sending.
## Limits
| Constraint | Limit |
| ------------------ | ----------------------------------- |
| Supported formats | PNG, JPEG |
| Maximum file size | 4 MB per image |
| Maximum dimensions | 8192 x 8192 pixels |
| Inputs per message | Up to 10 (text and images combined) |
Files that exceed these limits are rejected.
## When to use image attachments
* **UI bugs**: screenshot the broken UI and ask Ona to fix it
* **Design references**: attach a mockup and ask Ona to implement it
* **Error messages**: screenshot a stack trace or error dialog
* **Terminal output**: screenshot complex terminal output that is hard to copy as text
* **Diagrams**: share architecture diagrams or flowcharts for context
## Viewing images in sessions
Attached images appear inline in the session history. Click any image to open it in a lightbox for full-size viewing.
## Troubleshooting
Only PNG and JPEG files are supported. Other formats (GIF, WebP, SVG) are not accepted. Check that the file is under 4 MB and its dimensions do not exceed 8192 x 8192 pixels.
# Anthropic direct API (deprecated)
Source: https://ona.com/docs/ona/agents/llm-providers/anthropic
Maintain an existing direct Anthropic API integration in Ona.
**Direct Anthropic API integrations are deprecated and maintenance-only.** New integrations cannot be created.
Existing Enterprise integrations keep working and remain editable. You can rotate the API key, change the model, enable or disable the integration, or remove it.
## Manage an existing integration
1. Go to the [Runners settings page](https://app.ona.com/settings/runners).
2. Select the environment runner with the Anthropic integration.
3. Scroll down to the "LLM Providers" section.
4. Click **Edit** on the Anthropic integration to rotate the API key, change the model, or enable or disable the integration. You can also remove it from here.
## Verify the integration
1. Create a new environment with an enabled runner.
2. Open [Ona Agent](/docs/ona/agents/overview) and confirm it can access the configured Claude model.
3. Test the integration with a code generation request.
# AWS Bedrock Runtime (deprecated)
Source: https://ona.com/docs/ona/agents/llm-providers/bedrock
Maintain an existing Anthropic Claude integration through AWS Bedrock Runtime.
**AWS Bedrock Runtime integrations for Ona Agent are deprecated and maintenance-only.** Do not create new integrations.
Existing Enterprise integrations on AWS EC2 Runners keep working. You can update the model ID or token limit, or enable, disable, or remove the integration.
[AWS Bedrock Mantle](/docs/ona/agents/llm-providers/bedrock-mantle) is not deprecated. It provides OpenAI model access for Codex Agent.
This page documents existing IAM-based AWS Bedrock Runtime integrations that use `bedrock://` endpoints to provide Anthropic Claude models to Ona Agent.
## Requirements for existing integrations
* An AWS account with Bedrock enabled and access to the configured model.
* An Ona Enterprise organization.
* An AWS EC2 Runner in the same AWS account with IAM permissions to invoke Bedrock.
## Network access (VPC endpoints)
If your runner operates in a private subnet without internet egress, you need a VPC endpoint for the Bedrock Runtime service. Ona only calls the **Bedrock Runtime** API (`bedrock-runtime`). No other Bedrock endpoints are required.
Create an interface VPC endpoint for `com.amazonaws..bedrock-runtime` in the VPC where your runner is deployed. See the [AWS documentation on Bedrock VPC endpoints](https://docs.aws.amazon.com/bedrock/latest/userguide/vpc-interface-endpoints.html) for setup instructions.
## Maintain AWS permissions and model access
* Keep access to the configured Claude model enabled in the [AWS Bedrock console](https://console.aws.amazon.com/bedrock/).
* Keep the runner's IAM permissions to invoke the Bedrock Runtime API.
* Keep the configured model available in the runner's AWS region.
See the [AWS Bedrock Model Access documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html) for access requirements.
## Check the Bedrock endpoint
### Endpoint format
```bash theme={null}
bedrock://
```
Check the configured model ID against the [AWS Bedrock model names](https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html) for the runner's region.
## Verify an existing integration
1. Create a new environment with the configured runner.
2. Open [Ona Agent](/docs/ona/agents/overview) and start a session.
3. Test the integration with a code generation request.
## Supported models
Existing integrations support Claude model presets including **Claude Opus 4.8** and **Claude Sonnet 5** on AWS Bedrock.
### Identifying available models
There are two ways to identify models: **foundation models** and **inference profiles**. Inference profiles are resources that define a model and one or more regions for routing requests, enabling cross-region inference, usage tracking, and cost monitoring. Availability varies by region. Some regions only support foundation models, while others support both foundation models and inference profiles.
Check model availability per region in the [AWS documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/models-regions.html).
You can check availability using AWS CLI commands from your environment, assuming you have proper authentication and region environment variables set:
```bash theme={null}
# List available inference profiles
aws bedrock list-inference-profiles
# List available foundation models
aws bedrock list-foundation-models
```
### Testing model connectivity
To run a simple smoke test and verify a model works:
```bash theme={null}
# Set your foundation model or inference profile ID
export MODEL_ID="global.anthropic.claude-sonnet-5"
# Test the model with a simple request
aws bedrock-runtime invoke-model \
--model-id "$MODEL_ID" \
--body '{
"messages": [
{
"role": "user",
"content": "Hi there!"
}
],
"max_tokens": 50,
"anthropic_version": "bedrock-2023-05-31"
}' \
--cli-binary-format raw-in-base64-out
```
If the smoke test succeeds, the model should work with Ona Agent.
## Get help with an existing integration
If you encounter issues:
1. Check Ona Agent logs for detailed error messages.
2. Verify AWS quotas and Bedrock model access.
3. Contact your account manager for additional support.
## Troubleshooting
Use a model ID that is available in your runner's region. For regionalized models, use the correct prefix, such as `us.anthropic.*`.
Ensure the runner role has `bedrock:InvokeModel` and `bedrock:InvokeModelWithResponseStream`. Confirm model access is approved in the Bedrock console.
Use `bedrock://` and include the full version, such as `...-v1:0`.
Lower the maximum tokens with `gitpod runner config llm-integration set-max-tokens ...`. Review Bedrock service quotas and request increases if needed.
# AWS Bedrock Mantle
Source: https://ona.com/docs/ona/agents/llm-providers/bedrock-mantle
Set up AWS Bedrock Mantle for OpenAI model routing on an AWS EC2 runner
Available for Enterprise organizations where OpenAI model routing is enabled. [Contact sales](https://ona.com/contact/sales) to learn more.
This feature is only supported in **AWS EC2 Runners**.
Use AWS Bedrock Mantle when your AWS EC2 runner should route OpenAI model requests through a Bedrock Mantle endpoint.
This page covers the OpenAI setup exposed in Ona.
To track spend on your BYOK model usage, see the [AI cost usage API](/docs/ona/billing/cost-usage-api).
## Prerequisites
* Your organization has OpenAI model routing enabled.
* You have an AWS EC2 runner configured in Ona.
* You have a Bedrock Mantle endpoint and token.
* The runner can reach the Bedrock Mantle endpoint over HTTPS.
## Configure the endpoint
Use the Bedrock Mantle endpoint for your AWS region:
```bash theme={null}
https://bedrock-mantle..api.aws/openai/v1/responses
```
The Ona UI defaults to:
```bash theme={null}
https://bedrock-mantle.us-east-1.api.aws/openai/v1/responses
```
## Add the integration with the UI
1. Go to the [Runners settings page](https://app.ona.com/settings/runners).
2. Select the AWS EC2 runner where you want to configure Bedrock Mantle.
3. Scroll to **LLM Providers**.
4. Click **Configure**.
5. Select **AWS Bedrock Mantle**.
6. Enter your Bedrock Mantle endpoint.
7. Paste the Bedrock Mantle token into **API Key**.
8. Click **Create Integration**.
## Add the integration with the CLI
```bash theme={null}
gitpod runner config llm-integration create SUPPORTED_MODEL_OPENAI_AUTO https://bedrock-mantle..api.aws/openai/v1/responses
```
To verify the integration:
```bash theme={null}
gitpod runner config llm-integration list
```
## Verify the integration
1. Create a new environment with the configured AWS EC2 runner.
2. Start an agent that uses OpenAI model routing.
3. Confirm that the agent can answer a simple code question.
## Troubleshooting
AWS Bedrock Mantle is available only on AWS EC2 runners when OpenAI model routing is enabled for your organization. It is not shown on GCP runners.
Use an endpoint on the `bedrock-mantle..api.aws` domain. For OpenAI model routing, include the `/openai/v1/responses` path.
Confirm that the value in **API Key** is a Bedrock Mantle token. AWS Bedrock Mantle does not use the IAM-based credential flow from the AWS Bedrock Runtime integration.
# Google Vertex AI (deprecated)
Source: https://ona.com/docs/ona/agents/llm-providers/google-vertex
Maintain an existing Google Vertex AI integration in Ona.
**Google Vertex AI integrations are deprecated and maintenance-only.** New integrations cannot be created.
Existing Enterprise integrations keep working and remain editable. You can update the region, model version, or service account. You can also enable, disable, or remove the integration.
## Prerequisites for existing integrations
* Your runner must be able to reach `aiplatform.googleapis.com` over HTTPS. For runners that egress through a private VPC, this means either Private Google Access on the runner's subnet or a NAT gateway with outbound internet access. Without this, agent calls fail with connection errors.
* The Claude models you use must stay enabled in [Vertex AI Model Garden](https://console.cloud.google.com/vertex-ai/model-garden) for your project.
## Endpoint format
Existing integrations use endpoints of the form:
```bash theme={null}
vertex://${region}/${model-version}
```
Use the [global](https://cloud.google.com/blog/products/ai-machine-learning/global-endpoint-for-claude-models-generally-available-on-vertex-ai) region for dynamic routing across available infrastructure.
## Manage an existing integration
1. Go to the [Runners settings page](https://app.ona.com/settings/runners)
2. Select the runner with the Vertex integration
3. Scroll down to the "LLM Providers" section
4. Click **Edit** on the Vertex integration. You can update:
* **Region**: we recommend the global region for dynamic routing across available infrastructure.
* **Model Version**: for example `claude-sonnet-5`. See [Anthropic's model availability](https://docs.anthropic.com/en/api/claude-on-vertex-ai#model-availability).
* **Service Account JSON**: drag a new service account file here to replace the stored one.
You can also disable or remove the integration from here.
## Troubleshooting
**Authentication errors**
* Verify your service account has the correct IAM roles (`Vertex AI User`)
* Ensure the JSON key file is valid and properly formatted
* Check that the Vertex AI API is enabled for your project
**Endpoint not found**
* Verify your project ID, region, and model name in the endpoint URL
* Ensure the model is available in your selected region
**Permission denied**
* Check that your service account has `Vertex AI User` role
* Verify your project has billing enabled
* Ensure Vertex AI API is enabled
If you encounter issues:
1. Check the Ona Agent logs for detailed error messages
2. Verify your Google Cloud quotas and limits
3. Contact your account manager for additional support
# OpenAI direct API
Source: https://ona.com/docs/ona/agents/llm-providers/openai
Set up a runner LLM integration that connects directly to the OpenAI API
Available for Enterprise organizations where OpenAI model routing is enabled. [Contact sales](https://ona.com/contact/sales) to learn more.
Use the OpenAI direct API integration when your organization wants OpenAI model requests to use its own OpenAI API key. You can also configure an OpenAI-compatible endpoint.
This page covers organization-level runner configuration. To connect a user's ChatGPT plan for Codex, see [Connect Codex to ChatGPT](/docs/ona/integrations/configure-codex).
To track spend on your OpenAI direct API usage, see the [AI cost usage API](/docs/ona/billing/cost-usage-api).
## Prerequisites
* Your organization has OpenAI model routing enabled.
* You have an enterprise runner configured in Ona.
* The runner can reach your OpenAI or OpenAI-compatible endpoint over HTTPS.
* You have an OpenAI API key or the credentials required by your OpenAI-compatible endpoint.
## Add the integration with the UI
1. Go to the [Runners settings page](https://app.ona.com/settings/runners).
2. Select the runner where you want to configure the OpenAI direct API.
3. Scroll to **LLM Providers**.
4. Click **Configure**.
5. Select **OpenAI**.
6. Use `https://api.openai.com/v1` for direct OpenAI, or enter your OpenAI-compatible endpoint.
7. Paste the API key into **API Key**.
8. Click **Create Integration**.
## Add the integration with the CLI
```bash theme={null}
gitpod runner config llm-integration create SUPPORTED_MODEL_OPENAI_AUTO https://api.openai.com/v1
```
For an OpenAI-compatible endpoint, replace `https://api.openai.com/v1` with your endpoint URL. The URL may include a provider-specific path prefix and may end in `/v1`, `/v1/responses`, or `/v1/chat/completions`.
Ona preserves the prefix and completes requests to the required OpenAI API route.
To verify the integration:
```bash theme={null}
gitpod runner config llm-integration list
```
## Add custom request headers
Add custom request headers when your OpenAI-compatible gateway needs a routing value or details about the person who started the environment. For example, you can send a tenant name, email address, or employee ID with each model request.
Choose the header type based on the value you need:
* **Fixed value**: Sends the same value for every request.
* **User-specific value**: Builds the value from signed details about the environment creator when a Codex conversation starts.
### Send a fixed value
To add a literal header:
```bash theme={null}
gitpod runner config llm-integration set-header \
\
X-Gateway-Tenant \
tenant-a \
--type literal
```
`literal` is the default type, so `--type literal` is optional.
### Send a user-specific value
The following example reads an employee ID supplied by your identity provider:
```bash theme={null}
gitpod runner config llm-integration set-header \
\
X-Employee-ID \
'env_id_claims.creator_idp_claims["employee_id"]' \
--type cel-expression
```
User-specific values use Common Expression Language (CEL). Ona makes the signed environment token details available as `env_id_claims`. Common fields include `creator_id`, `creator_email`, and `creator_idp_claims`. See [environment token claims](/docs/ona/configuration/oidc#environment-tokens) for the full list.
User-specific values apply to Codex Agent conversations. Other agents send fixed headers but do not evaluate CEL expressions.
### Review or remove headers
List the configured names and effective types:
```bash theme={null}
gitpod runner config llm-integration list-headers
```
The command never prints literal values or CEL expressions. To remove a header:
```bash theme={null}
gitpod runner config llm-integration remove-header X-Employee-ID
```
If Ona cannot read the signed environment details or resolve an expression, the model request continues without the affected header. Other configured headers remain attached, and the conversation shows a configuration warning without exposing header values.
## Verify the integration
1. Create a new environment with the configured runner.
2. Start an agent that uses OpenAI model routing.
3. Confirm that the agent can answer a simple code question.
## Troubleshooting
The OpenAI direct API integration is available only when OpenAI model routing is enabled for your organization. Contact your account manager if you expect this option to be available.
Verify that the API key is active and has access to the OpenAI endpoint you configured. If you use an OpenAI-compatible endpoint, confirm that the endpoint expects the same bearer-token authentication format.
Confirm that the runner can reach the endpoint over HTTPS. If the runner is in a private network, check outbound routing, firewall rules, and any proxy configuration required by your network.
# Model access
Source: https://ona.com/docs/ona/agents/llm-providers/overview
Understand default model access, Codex Agent ChatGPT plan support, and custom token providers.
On Ona Cloud, Ona provides OpenAI model access for Codex Agent by default, with no configuration required. Customer-managed runners require OpenAI model access through Ona Intelligence or an approved OpenAI-compatible provider.
Ona Agent and Ona-managed Anthropic model access are no longer available on Ona Cloud. Use Codex Agent with OpenAI model access for new sessions and automations.
Use Ona-managed model access unless your Enterprise organization has an approved requirement to bring its own provider credentials.
To see how much your organization uses, query the [Ona Intelligence usage API](/docs/ona/billing/ona-intelligence-usage-api) for Ona-managed models, or the [AI cost usage API](/docs/ona/billing/cost-usage-api) if you bring your own provider keys (BYOK).
## Codex Agent model access
Codex Agent is available on Ona Cloud and supported customer-managed runners.
On Ona Cloud, Codex Agent can run using the model access available to the organization. Core users can also connect their ChatGPT account so Codex model requests use their ChatGPT plan.
On a customer-managed runner, Codex Agent uses OpenAI model access provided by Ona Intelligence or an OpenAI-compatible LLM integration configured for that runner. See [OpenAI direct API](/docs/ona/agents/llm-providers/openai) for setup.
See [Codex Agent](/docs/ona/agents/codex) for how Codex works in Ona. To use your ChatGPT plan for Codex model requests, see [Connect Codex to ChatGPT](/docs/ona/integrations/configure-codex).
## Custom token providers
Custom token providers are available by exception for Enterprise customers. If you have a requirement to use your own token provider, [contact sales](https://ona.com/contact/sales) to discuss.
For approved custom provider setups, see the provider-specific guides for [OpenAI direct API](/docs/ona/agents/llm-providers/openai) and [AWS Bedrock Mantle](/docs/ona/agents/llm-providers/bedrock-mantle). The [AWS Bedrock Runtime](/docs/ona/agents/llm-providers/bedrock), [Google Vertex AI](/docs/ona/agents/llm-providers/google-vertex), and [direct Anthropic API](/docs/ona/agents/llm-providers/anthropic) integrations are deprecated and maintenance-only.
# Mermaid diagrams
Source: https://ona.com/docs/ona/agents/mermaid-diagrams
Visualize architecture, dependencies, and workflows with agent-generated diagrams
Agents in Ona can generate Mermaid diagrams to visualize system architecture, dependencies, workflows, and data relationships. Ask in natural language and the agent produces a rendered diagram.
**Example prompts:**
* "Draw an architecture diagram showing how our microservices communicate"
* "Create a sequence diagram for the authentication flow"
* "Show me a dependency graph for the frontend components"
* "Visualize the relationships between our database tables"
## When Mermaid is useful
Mermaid diagrams help compress code or process detail into something you can scan quickly.
Common use cases:
* Architecture overviews for onboarding
* Sequence diagrams for request or authentication flows
* Dependency maps for refactors
* Entity diagrams for schema discussions
* Workflow diagrams for automations and pipelines
## Supported diagram types
* **Flowcharts**: decision trees and process flows
* **Sequence diagrams**: interaction between components over time
* **Class diagrams**: object-oriented relationships
* **Entity-relationship diagrams**: database schema visualization
* **State diagrams**: state machines and transitions
* **Gantt charts**: project timelines
See the [Mermaid documentation](https://mermaid.js.org/) for syntax reference.
## Viewing diagrams
Diagrams render with **Code** and **Preview** tabs. The preview includes zoom controls (25% to 450%), fullscreen mode, and copy-to-clipboard.
Use the **Code** tab when you want to review or tweak the Mermaid syntax, copy the diagram into another document, or ask the agent to fix a rendering problem.
## Refining a diagram
The first diagram is often a draft. Good follow-up prompts include:
* "Simplify this to the five most important components"
* "Turn this into a sequence diagram"
* "Group frontend, backend, and infrastructure separately"
* "Remove low-level implementation detail and focus on data flow"
## Troubleshooting
The Mermaid syntax is invalid. Ask the agent to fix it or check the code tab for syntax issues.
Ask for fewer nodes, clearer grouping, or a different diagram type.
# Ona Agent (deprecated)
Source: https://ona.com/docs/ona/agents/overview
Reference documentation for Enterprise organizations that still use Ona Agent.
**Ona Agent is deprecated.** Use [Codex Agent](/docs/ona/agents/codex) for all new environments and automations.
Ona Agent and Ona-managed Anthropic model access are no longer available on Ona Cloud. Existing Ona Cloud automations use Codex Agent automatically. No action is required.
Enterprise organizations with customer-managed Anthropic model access can continue using Ona Agent for now, but should plan to move their workloads to Codex Agent.
Customer-managed Claude Code running inside an Ona environment is not affected.
Ona Agent is Ona's custom Anthropic agent harness. It writes code, runs tests, and opens pull requests in isolated environments while respecting your organization's security policies and guardrails. This page documents Ona Agent for Enterprise organizations that still use customer-managed Anthropic model access.
## What Ona Agent can do
* **Write and modify code**: features, bug fixes, refactors, tests, documentation
* **Run your toolchain**: commands, formatters, linters, test suites in isolated environments
* **Manage pull requests**: open branches, create PRs, respond to review feedback
* **Execute long-running work**: migrations, large refactors, multi-repo changes (see [Automations](/docs/ona/automations/overview))
* **Follow your policies**: command allow/deny lists, SSO, audit logging
## How Ona Agent works
Give Ona Agent a task through chat, a Linear issue, or an automation trigger. It spins up an isolated environment using your Dev Container configuration, works through the task on its own, and opens a pull request when it's done.
Each environment is isolated from your machine and other environments. If something goes wrong, discard it and start fresh.
For how agents fit into the broader platform, see [Core Components](/docs/ona/understanding/core-components#agents).
## Prerequisites
* An Enterprise plan.
* Customer-managed Anthropic model access on a supported [AWS](/docs/ona/runners/aws/overview) or [GCP](/docs/ona/runners/gcp/overview) runner.
## Configure Ona Agent
* **Teach agents your codebase**: create an [AGENTS.md](/docs/ona/agents-md) with your conventions, or add [Skills](/docs/ona/agents-md#skills-for-multi-step-workflows) for repo-specific workflows
* **Organization-level skills**: codify your team's workflows with [skills](/docs/ona/skills) that agents discover proactively
* **Connect integrations**: enable [Linear](/docs/ona/integrations/configure-linear) or other [integrations](/docs/ona/integrations/overview) for richer context
* **Set guardrails**: configure [command deny lists](/docs/ona/command-deny-list), [executable deny lists](/docs/ona/organizations/policies/executable-deny-list), and [policies](/docs/ona/organizations/policies/scm-tools) for safe execution
## Best practices
* Start with smaller tasks and expand scope as you build confidence
* Keep environments reproducible with Dev Containers and Tasks
* Use guardrails for safe, auditable execution
* Test workflows in non-production repositories before broad rollout
## Next steps
* [Codex Agent](/docs/ona/agents/codex): move workloads to the open-source Codex harness
* [AGENTS.md](/docs/ona/agents-md): teach agents your conventions
* [Skills](/docs/ona/skills): create reusable prompts agents discover proactively
* [MCP servers](/docs/ona/mcp): extend agent capabilities
* [Command deny list](/docs/ona/command-deny-list): restrict dangerous commands
* [Executable deny list](/docs/ona/organizations/policies/executable-deny-list): block specific binaries at the kernel level
# GitHub, GitLab & Bitbucket tools
Source: https://ona.com/docs/ona/agents/scm-tools
Built-in tools for managing pull requests, issues, and code reviews
Agents in Ona include built-in tools for GitHub, GitLab, and Bitbucket Cloud. They can create pull requests, manage issues, add code review comments, and search repositories without additional configuration beyond connecting your source control provider.
**Supported providers:** GitHub (including Enterprise), GitLab (including self-hosted), Bitbucket Cloud
Azure DevOps supports [repository access](/docs/ona/source-control/overview) but agent tools are not yet available. Bitbucket Server / Data Center is not yet supported. Only Bitbucket Cloud (bitbucket.org) is supported.
## Capabilities
* Create, update, read, and merge pull requests and merge requests
* Add, update, and delete general and inline code review comments
* Create, update, and manage issues and issue comments
* Search issues and pull requests
* Read workflow runs (GitHub Actions) and pipeline status (GitLab)
**Example prompts:**
* "Create a pull request for my changes titled 'Add input validation'"
* "Review PR #42 and add inline comments for issues you find"
* "Create an issue for refactoring the authentication module"
* "Search for open issues related to 'timeout errors'"
## Organization controls
SCM tools are enabled by default. Administrators can configure access in [Settings > Agents > Policies](https://app.ona.com/settings/agent-policies):
* **Enabled for all members** (default)
* **Enabled for specific group**: gradual rollout or team restrictions
* **Disabled**: agents use git commands only, no PR/issue tools
When disabled, agents can still clone, commit, and push but cannot interact with the GitHub/GitLab/Bitbucket API.
## Provider differences
| Feature | GitHub | GitLab | Bitbucket Cloud |
| --------------- | --------------- | ------------------ | ------------------- |
| Inline comments | Direct comments | Discussion threads | Inline comments |
| Draft PRs/MRs | Supported | Supported | Supported |
| Assignees | Username-based | Requires user IDs | Not supported |
| Issues | Full support | Full support | Not supported |
| CI status | GitHub Actions | Pipelines | Bitbucket Pipelines |
## Prerequisites
1. [Configure source control](/docs/ona/source-control/overview) on your runner.
2. Authorize via OAuth or PAT when creating your first environment.
**Required scopes:**
* GitHub: `repo`, `read:user`, `workflow` (if editing Actions files)
* GitLab: `api`, `read_repository`, `read_user`
* Bitbucket Cloud: `account`, `pullrequest:write`, `pipeline` (`pullrequest:write` implicitly grants `pullrequest`, `repository:write`, and `repository`)
## Limitations
* Cannot sync PR branches with base branch
* Cannot approve or request changes on PRs
* Bitbucket Cloud: no issue tracking tools (Bitbucket issues API is limited)
## Troubleshooting
Verify source control is configured and you have authorized access. Restart your environment to reload tools.
Check token scopes and repository permissions. For GitHub organizations, ensure [OAuth app access is granted](/docs/ona/source-control/github#granting-access-to-additional-github-organizations).
# Skills
Source: https://ona.com/docs/ona/agents/skills
Teach agents to follow your workflows automatically.
Skills are `SKILL.md` files containing step-by-step workflow instructions. They teach agents to follow specific workflows, such as creating PRs, deploying to staging, or writing tests in a particular style. When a task matches a skill's description, the agent reads and follows those instructions.
Skills come from three places, plus `AGENTS.md` for general codebase context:
| Feature | Repository skills | Organization skills | Built-in skills | AGENTS.md |
| ------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------- |
| **Where they live** | `.ona/skills//SKILL.md` (also `.claude/skills/` and `.agents/skills/`) in the repo | Configured in [Settings → Agents → Skills](https://app.ona.com/settings/agent-skills) | Shipped with the agent | `AGENTS.md` in the repo |
| **Scope** | Repository | Whole organization | All users | Repository |
| **Discovery** | Automatic by description | Automatic by agent, or user invokes with `/` | Automatic by description | Always loaded |
| **Best for** | Codebase-specific workflows | Team-wide reusable prompts and slash commands | Common workflows like `browse-web`, `ona-docs`, `devcontainer-setup`, `skill-creator` | Project conventions and general context |
When two sources publish a skill with the same name, **repository skills win over organization skills, which win over built-in skills**. This lets a repo customize a team-wide workflow, or a team override a built-in one.
## Skill structure
```markdown theme={null}
---
name: skill-name
description: What this skill does and when to use it
---
# Skill Title
## Steps
1. **Step one** - Clear instruction
2. **Step two** - Include commands where helpful
## Anti-patterns
- What NOT to do
```
Here are some skills the Ona engineering team uses:
```markdown theme={null}
---
name: create-pr
description: Create pull requests following repository conventions. Use when asked to create a PR, open a PR, or land changes.
---
# Create PR
## Steps
1. **Clean up code** - remove obvious comments from new/changed code
2. **Format** - run `gofmt` (Go) or `prettier` (JS/TS)
3. **Lint** - run `golangci-lint run ./...` (Go) or `eslint` (JS/TS)
4. **Create branch** - `/` (max 24 chars)
5. **Commit** - use Conventional Commits
6. **Push** - `git push -u origin `
7. **Open draft PR** - use `.github/pull_request_template.md`
## Anti-patterns
- Don't use superlatives in commits or PR descriptions
- Don't commit unrelated changes
- Don't push to main directly
```
```markdown theme={null}
---
name: go-tests
description: Generates Go unit tests using the Expectation pattern with cmp.Diff. Use when writing or fixing Go tests.
---
# Go Tests
Table-driven tests using the Expectation pattern with `cmp.Diff`.
## Rules
1. **Always use `t.Parallel()`** at test function and subtest level
2. **Never use `t.Parallel()` with `t.Setenv()`** - they panic together
3. **Single `cmp.Diff` assertion** comparing entire Expectation struct
4. **Capture errors as strings** in `Expectation.Err`, not with `t.Fatal`
5. **Never use testify** - use `cmp.Diff` only
## Anti-Patterns
- `t.Fatal` for action errors → use `Expectation.Err`
- `context.Background()` → use `t.Context()`
- `testify/assert` → use `cmp.Diff`
```
Requires [Linear integration](/docs/ona/integrations/configure-linear).
```markdown theme={null}
---
name: linear-ticket
description: Create Linear tickets from code analysis. Use when asked to create a ticket, file an issue, or track work in Linear.
---
# Create Linear Ticket
Create a well-structured Linear ticket from the current context.
## Steps
1. **Gather context** - Understand what needs to be tracked (bug, feature, task)
2. **Check for duplicates** - Search Linear for existing tickets on the same topic
3. **Create ticket** - Use appropriate team, labels, and priority
4. **Link resources** - Attach relevant PRs, files, or documentation
## Ticket format
- **Title**: Clear, actionable (`Fix auth timeout on slow connections`)
- **Description**: Include reproduction steps for bugs, acceptance criteria for features
- **Labels**: Add relevant labels (bug, feature, tech-debt)
## Anti-patterns
- Don't create duplicate tickets
- Don't leave description empty
- Don't assign without checking availability
```
```markdown theme={null}
---
name: sentry-triage
description: Find and triage Sentry errors. Creates a Linear ticket with analysis.
---
# Sentry Triage
Find the highest-impact untriaged Sentry error and create ONE Linear ticket.
## Steps
1. **Find first untriaged issue** - Query Sentry for unresolved errors in last 24 hours, sorted by event count
2. **Skip if tracked** - Search Linear for existing ticket with Sentry ID
3. **Check if already fixed** - Look for recent commits that address the error
4. **Analyze** - Get stacktrace, identify root cause, classify as bug/false-positive/noise
5. **Create Linear issue** - Title includes Sentry ID, description has stacktrace and fix assessment
## What this skill does NOT do
- Does NOT implement fixes (use `sentry-fix` skill)
- Does NOT process multiple issues per run
```
```markdown theme={null}
---
name: sentry-fix
description: Implement a fix for a triaged Sentry issue and create a PR. Use when given a Linear issue ID to fix.
---
# Sentry Fix
Implement a fix for a triaged Sentry issue and create a PR.
**Input**: Linear issue ID (e.g., `AGENT-1646`)
**Output**: PR URL, or explanation why fix was not attempted
## Steps
1. **Get issue context** - Fetch Linear issue, extract Sentry link and fix assessment
2. **Validate** - Confirm root cause documented, fix location identified, change is mechanical
3. **Implement** - Read target file, apply fix following codebase patterns
4. **Create PR** - Use `create-pr` skill, include Sentry issue ID for auto-resolution
## Anti-patterns
- Never hide bugs by changing log levels for genuinely unexpected conditions
- Stop if uncertain — let humans decide
```
## Create a skill
Skills live in your repository.
1. Create a directory in `.ona/skills/`:
```bash theme={null}
mkdir -p .ona/skills/create-pr
```
2. Create a `SKILL.md` file:
```markdown theme={null}
---
name: create-pr
description: Create pull requests following repository conventions
---
# Create Pull Request
## Steps
1. **Run checks**: `npm test && npm run lint`
2. **Create branch**: `initials/short-description`
3. **Create PR**: Use template, link issues
## Anti-patterns
- PRs with failing tests
- Skipping the PR template
```
3. Commit to your repository:
```bash theme={null}
git add .ona/skills/create-pr/
git commit -m "Add create-pr skill"
```
### Directory structure
```
.ona/skills/
├── create-pr/
│ └── SKILL.md
├── deploy-staging/
│ └── SKILL.md
└── debug-performance/
└── SKILL.md
```
### SKILL.md format
**Required fields**:
* `name`: Unique identifier. If omitted, defaults to the directory name
* `description`: When to use this skill. Be specific and include trigger words
**Naming conventions**:
* Lowercase letters, numbers, and hyphens
* Maximum 64 characters
* Avoid vague names: `helper`, `utils`, `tools`
## How agents discover skills
At session start, the agent collects skills from three sources:
1. **Repository skills** in `.ona/skills/`, `.claude/skills/`, or `.agents/skills/` of the current repo
2. **Organization skills** configured for your Ona organization
3. **Built-in skills** that ship with the agent
Each source contributes a list of skills (name + description). Full skill content is loaded on demand via `read_skill` when a task matches a skill's description. When two sources publish a skill with the same name, repository skills win over organization skills, and organization skills win over built-in skills.
## Best practices
### Write specific descriptions
The description determines when the agent uses the skill:
* ✅ "Create pull requests following repository conventions. Use when asked to create a PR, open a PR, or land changes."
* ❌ "PR stuff"
### Design for stability
* Use concepts that remain valid despite refactoring
* Let the agent rediscover current code state rather than hardcoding paths
* If tools can't do something, drop it
### Keep skills focused
One skill per workflow. Keep `SKILL.md` under 500 lines. Move reference material to separate files.
### Include anti-patterns
Tell the agent what not to do. This prevents common mistakes.
### Reference, don't duplicate
```markdown theme={null}
## Database migrations
See [migrations guide](./docs/migrations.md) for the full process.
```
## Next steps
* [AGENTS.md](/docs/ona/agents-md): general codebase context
* [Organization skills](/docs/ona/skills): team-wide reusable prompts with optional slash commands
* [Automations](/docs/ona/automations/overview): run workflows automatically
## Troubleshooting
**Check the description**: Be specific about when to use it and include trigger words.
**Check the path**: Skills must be in `.ona/skills//SKILL.md` (or `.claude/skills/` or `.agents/skills/`)
**Check path**: Ensure the file is at `.ona/skills//SKILL.md` (or `.claude/skills/` or `.agents/skills/`)
**Check frontmatter**: Ensure YAML is valid with required `name` and `description` fields
# Automations as Code
Source: https://ona.com/docs/ona/automations/automations-as-code
Define, version, and share Automations using YAML files and the Ona CLI.
Define Automations as YAML files and manage them with the Ona CLI.
## Why define Automations as code
* **Version control.** Track changes in Git. Review diffs, revert mistakes, use branches.
* **Reproducibility.** The YAML file is the source of truth. No UI clicks to reconstruct a lost Automation.
* **Distribution.** Commit Automation files to any repository. Team members run `ona ai automation create` to instantiate them.
## Prerequisites
* [Ona CLI](/docs/ona/integrations/cli) installed and authenticated (`ona login`)
## Discover the YAML syntax
Generate a reference file covering the full syntax:
```bash theme={null}
ona ai automation create --example > automation.yaml
```
## Create an Automation from a file
```bash theme={null}
ona ai automation create automation.yaml
```
On success, the CLI prints the new Automation ID:
```
Successfully created ai automation a1b2c3d4-5e6f-7890-abcd-ef1234567890
```
Stdin is also supported:
```bash theme={null}
cat automation.yaml | ona ai automation create -
```
## Update an existing Automation
Find the Automation ID:
```bash theme={null}
ona ai automation list
```
Apply the updated file:
```bash theme={null}
ona ai automation update automation.yaml
```
Provided fields replace existing values. Fields not in the YAML remain unchanged. Complex fields like `triggers` and `action` are replaced entirely, not merged.
## Real-world example
[ona-samples/github-security](https://github.com/ona-samples/github-security) contains two Automation files that pick the highest-severity open security alert, fix it, run tests, and open a PR:
* [`.ona/fix-dependabot-alert.yaml`](https://github.com/ona-samples/github-security/blob/main/.ona/fix-dependabot-alert.yaml) — upgrades vulnerable dependencies flagged by Dependabot
* [`.ona/fix-codescan-alert.yaml`](https://github.com/ona-samples/github-security/blob/main/.ona/fix-codescan-alert.yaml) — fixes code scanning findings from CodeQL, Trivy, or OSV-Scanner
```bash theme={null}
ona ai automation create .ona/fix-dependabot-alert.yaml
ona ai automation create .ona/fix-codescan-alert.yaml
```
## Next steps
* [Creating Automations](/docs/ona/automations/configure-automations) — UI-based setup
* [Automations in practice](/docs/ona/automations/automations-in-practice) — real-world templates
* [Report step](/docs/ona/automations/report-step) — structured data extraction
* [CLI reference](/docs/ona/reference/cli) — full command reference
# Automations in practice
Source: https://ona.com/docs/ona/automations/automations-in-practice
Set up five real-world Automations: Sentry triage, autonomous backlog picker, Knip cleanup, CVE remediation, and migrations at scale.
Your Sentry dashboard has 40 unresolved errors. Your Linear backlog has 30 issues in the current sprint, and realistically you will get to maybe five of them today. You could spend the morning triaging each one, reading stack traces, and context-switching between tools. Or you could set up Automations that triage errors, trace them to source code, and open fix PRs while you focus on design decisions and code review.
This guide walks through five Automations that cover the most common use cases: **Sentry error triage and fix**, **Autonomous backlog picker (10x engineer)**, **Codebase cleanup with Knip**, **CVE remediation with Snyk or Aikido**, and **Migrations at scale**.
Automations work best with [projects](/docs/ona/projects/overview). A project provides the Dev Container configuration, dependencies, and environment settings that your Automation runs against. All templates in this guide assume you have a project set up for your repository. See [Create your first project](/docs/ona/create-first-project).
## Sentry error triage and fix
This template queries Sentry for unresolved errors, traces the highest-impact one to source code, applies a fix, and opens a pull request.
### What it does
The Automation runs four steps in sequence:
1. **Triage.** Queries Sentry for unresolved issues from the past 24 hours, sorted by event count. Selects the top unassigned issue and extracts the title, error message, stack trace, event count, and affected users.
2. **Root cause analysis.** Locates the exact file and line in your repository using the stack trace. Identifies the error category (null reference, type error, unhandled exception, race condition, etc.) and explains the root cause.
3. **Fix.** Applies the minimal change needed to resolve the root cause. Adds or updates tests to cover the error scenario. Runs the test suite and iterates until tests pass.
4. **Pull request.** Opens a PR with the fix, linking back to the Sentry issue.
### Prerequisites
* Ona account with Automations enabled
* [Sentry integration](/docs/ona/integrations/overview) configured for your organization
* A project with a connected repository that reports errors to Sentry
### Set up the Automation
1. Navigate to **Automations** in the left panel and click **New**.
2. Select the **Sentry error triage and fix** template. If the [Sentry integration](/docs/ona/integrations/configure-sentry) is not configured, a **Required Integrations** dialog appears. Follow the links to enable the integration in **Organization settings > Integrations** and connect it with your personal account in **User settings > Integrations**. The **Create** button is disabled until all required integrations are configured.
3. Under **Trigger**, the default is [**Manual**](/docs/ona/automations/triggers/manual). Keep this for your first run. Switch to a daily schedule later.
4. Under **Projects**, select the project whose repository reports to Sentry.
5. Click **Save**.
### Run it
1. Open the Automation and click **Run**.
2. The execution view shows each step as it progresses:
* Step 1 queries Sentry and selects an error
* Step 2 traces the stack trace to your codebase
* Step 3 applies the fix and runs tests
* Step 4 opens the pull request
Expand any step to see the agent's reasoning and the commands it ran:
### Review the result
The Automation opens a pull request with:
* The fix applied to the affected file(s)
* New or updated tests covering the error scenario
* A description linking to the Sentry issue and explaining the root cause
Review the PR as you would any other. Check the fix, verify the tests, and merge when satisfied.
### Tips
* **Start manual.** Run the Automation a few times manually to build confidence in the results before scheduling it.
* **Schedule regularly.** Once you trust the output, switch the trigger to scheduled. Use **Every day** for daily runs, or **Every weekday** for weekday mornings at 9 AM UTC.
* **Pair with Sentry to Linear issues.** The "Sentry to Linear issues" template creates Linear tickets from Sentry errors. Combined with this template, you get a full pipeline: detect, ticket, fix, PR.
## Autonomous backlog picker (10x engineer)
This template runs every weekday morning, picks your highest-priority Linear issue, implements it, runs tests, and opens a draft PR.
### What it does
The Automation runs five steps:
1. **Fetch candidates.** Queries Linear for issues assigned to you in the current sprint. Sorts by priority (urgent first), then due date. Excludes issues already in progress, in review, or done. Returns the top 5 candidates.
2. **Evaluate feasibility.** For each candidate, analyzes the repository to determine if the issue can be implemented end-to-end: clear requirements, contained scope, testable, no external infrastructure changes needed. Picks the first feasible issue.
3. **Code.** Updates the Linear issue status to "In Progress," then writes the changes following existing code patterns. Adds tests for new functionality and handles edge cases from the acceptance criteria.
4. **Test.** Runs the project's test suite (`npm test`, `go test ./...`, or equivalent).
5. **Pull request.** Opens a draft PR linking to the Linear issue. Updates the issue status to "In Review."
### Prerequisites
* Ona account with Automations enabled
* [Linear integration](/docs/ona/integrations/overview) configured for your organization and your user account
* A [project](/docs/ona/projects/overview) with a connected repository
* Issues assigned to you in the current sprint/cycle with clear acceptance criteria
### Set up the Automation
1. Navigate to **Automations** and select the **10x engineer** template. If the [Linear integration](/docs/ona/integrations/configure-linear) is not configured, a **Required Integrations** dialog appears — follow the links to enable and connect it before proceeding.
2. Under **Trigger**, the default is [**Scheduled**](/docs/ona/automations/triggers/timebased): every weekday at 9 AM UTC. Adjust the time to match your morning routine.
3. Under **Projects**, select the project you want the Automation to work on.
4. Click **Save**.
### Run it
The Automation fires on schedule. Each morning:
1. It picks your top issue from Linear.
2. Implements the change in your repository.
3. Runs tests.
4. Opens a draft PR.
You review the draft PR over coffee. If the implementation looks good, mark it ready for review and merge. If it needs changes, leave comments. The next run will pick a different issue.
If none of the top 5 candidates are feasible (too large, unclear requirements, requires infrastructure changes), the Automation stops early and reports why. This is expected. Not every issue is automatable.
### Tips
* **Keep your backlog prioritized.** The Automation picks the highest-priority issue. If your backlog is unsorted, it may pick something low-value.
* **Use labels to curate candidates.** Add a label like `good-for-ona` to issues that are well-scoped and automatable, then adjust the prompt to filter by that label. This gives you explicit control over what the Automation picks up.
* **Start with well-scoped issues.** Bug fixes, small features, and refactors with clear acceptance criteria work best. Exclude epics and large issues.
* **Review the draft PRs.** These are drafts for a reason. Treat them as a starting point, not a finished product.
## Codebase cleanup with Knip
This Automation combines a deterministic command ([Knip](https://knip.dev/)) with the agent to find and remove unused code. It keeps the codebase clean and context windows tight for other agents.
### What it does
The Automation runs three steps:
1. **Scan.** Runs Knip against the repository to detect unused JS/TS dependencies, exports, types, and files.
2. **Clean up.** The agent removes the unused code identified by Knip. Creates small, focused changes that are quick to review.
3. **Pull request.** Opens a PR with automerge enabled. Each PR addresses one category of unused code (dependencies, exports, or files) to keep reviews manageable.
### Prerequisites
* Ona account with Automations enabled
* A [project](/docs/ona/projects/overview) with a connected JS/TS repository
* Knip installed as a dev dependency or available in your Dev Container
### Set up the Automation
1. Navigate to **Automations** and click **New**.
2. Select **Start from scratch**.
3. Add a **Command** step that runs Knip and captures the output:
```bash theme={null}
npx knip --reporter json > knip-report.json
```
4. Add a **Prompt** step:
```
Read knip-report.json. For each category of unused code (dependencies, exports, files),
remove the unused items. Run the test suite after each change to verify nothing breaks.
```
5. Add a **Pull Request** step with automerge enabled.
6. Under **Trigger**, select **Scheduled** with a weekly schedule (e.g., `0 8 * * 1` for Monday mornings).
7. Under **Projects**, select the target project.
8. Click **Save**.
### Run it
Run the Automation manually first to verify the results. Knip may flag items that are used dynamically or through non-standard imports. Review the first few PRs carefully and adjust the Knip configuration if needed.
Once confident, let the weekly schedule handle it. Each Monday morning, you get a small PR removing dead code.
### Tips
* **Configure Knip first.** Add a `knip.json` or `knip.ts` config to exclude known dynamic imports and entry points. This reduces false positives.
* **Enable automerge.** Knip cleanup PRs are low-risk if your test suite is solid. Automerge keeps the process hands-off.
* **Pair with CI.** Add Knip to your CI pipeline so new unused code is caught at PR time, not only during weekly cleanup.
## CVE remediation with Snyk or Aikido
This Automation runs security scanning CLIs against your projects, resolves all found CVEs, and creates standardized PRs. Schedule it for off-hours and review clean PRs the next morning.
### What it does
The Automation runs four steps:
1. **Scan.** Runs the security CLI (Snyk, Aikido, or similar) against the repository to identify CVEs.
2. **Remediate.** The agent resolves each CVE: upgrades dependencies, applies patches, or migrates breaking API changes.
3. **Verify.** Reruns the security scan to confirm all CVEs are resolved. Runs the test suite to verify nothing breaks. Iterates until both pass.
4. **Pull request.** Opens a PR with a summary of resolved CVEs, linking to advisory details.
### Prerequisites
* Ona account with Automations enabled
* A [project](/docs/ona/projects/overview) with a connected repository
* Snyk CLI, Aikido CLI, or equivalent installed in your Dev Container
* API token for the security tool stored as a [secret](/docs/ona/configuration/secrets/overview)
### Set up the Automation
1. Navigate to **Automations** and click **New**.
2. Select **Start from scratch**.
3. Add a **Command** step that runs the security scan:
```bash theme={null}
snyk test --json > snyk-report.json
```
4. Add a **Prompt** step:
```
Read snyk-report.json. Resolve every CVE found: upgrade dependencies, apply patches,
or migrate breaking changes. After each fix, rerun "snyk test" to verify the CVE is resolved.
Run the test suite to confirm nothing breaks. Iterate until "snyk test" reports zero vulnerabilities.
```
5. Add a **Pull Request** step.
6. Under **Trigger**, select **Scheduled** with an off-hours schedule (e.g., `0 20 * * 0` for Sunday at 8 PM UTC).
7. Under **Projects**, select the target projects.
8. Click **Save**.
### Run it
Run manually first against a single repository. Review the PR to verify the fixes are correct and tests pass. Once confident, enable the schedule.
Every execution gets the exact same tooling. The environment is reproducible, so results are consistent across runs.
### Tips
* **Schedule for off-hours.** Sunday evening is ideal. Review clean PRs Monday morning.
* **Run across multiple repos.** Select multiple projects to scan your entire organization in parallel.
* **Combine with compliance reporting.** The Automation's execution log provides an audit trail of what was scanned, what was found, and what was fixed.
## Migrations at scale
This Automation handles large-scale migrations by batching repositories on a schedule and creating incremental, reviewable PRs. Examples: CI pipeline migration (GitLab CI to GitHub Actions), Java 8 to 17 upgrades, JavaScript to TypeScript conversion.
### What it does
The Automation runs three steps per repository:
1. **Analyze.** The agent reads the repository to understand the current state and determine what needs to change for the migration.
2. **Migrate.** Applies the migration changes incrementally. Runs the test suite after each change to verify correctness.
3. **Pull request.** Opens a PR with the migration changes and a description of what was changed and why.
### Prerequisites
* Ona account with Automations enabled
* [Projects](/docs/ona/projects/overview) set up for each repository in the migration batch
* A clear migration specification (what to change, what the target state looks like)
### Set up the Automation
1. Navigate to **Automations** and click **New**.
2. Select **Start from scratch**.
3. Add a **Prompt** step with your migration specification. Be specific about the target state:
```
Migrate this repository from GitLab CI (.gitlab-ci.yml) to GitHub Actions (.github/workflows/).
Convert each CI job to an equivalent GitHub Actions workflow. Preserve all environment variables,
secrets references, and deployment targets. Run the test suite to verify the migration.
Delete the .gitlab-ci.yml file after all workflows are verified.
```
4. Add a **Pull Request** step.
5. Under **Trigger**, select **Scheduled** with a batched schedule (e.g., `0 22 * * 0` for Sunday at 10 PM UTC).
6. Under **Projects**, select a batch of repositories (e.g., 10 at a time).
7. Set **Guardrails**: max parallel 10, max total 10.
8. Click **Save**.
### Run it
Start with a small batch (2-3 repos) to validate the migration logic. Review the PRs carefully. Once the pattern is proven, increase the batch size.
Each Sunday night, the Automation migrates the next batch. Engineers review the PRs Monday morning. Over a few weeks, the entire organization is migrated.
### Tips
* **Batch deliberately.** Start with simple repositories (few CI jobs, standard configurations) and progress to complex ones.
* **Write a detailed migration spec.** The more specific the prompt, the more consistent the results across repositories.
* **Track progress externally.** Use a spreadsheet or Linear project to track which repositories have been migrated, which are in progress, and which remain.
* **Combine with a PR trigger.** After the migration PR is merged, use a PR-triggered Automation to verify the new CI pipeline runs successfully.
## How they connect
These five Automations address different parts of the development cycle but complement each other naturally.
The Sentry template finds and fixes production errors. If you also use the **Sentry to Linear issues** template, those errors become Linear tickets. The Autonomous backlog picker then picks those tickets up automatically in the next morning run.
Knip cleanup keeps the codebase lean, which improves the accuracy and speed of every other Automation. CVE remediation handles security debt on a schedule. Migrations at scale tackles the large projects that slip every quarter.
Together, they create a loop: **detect, triage, fix, clean, ship**.
## Scaling across repositories
The templates above work on a single project and repository. As your usage grows, run the same Automation across multiple repositories in parallel. For example, scanning and fixing Sentry errors across dozens of repos simultaneously. The number of parallel actions depends on your plan. See [Plans and limits](/docs/ona/automations/plans-and-limits) for details.
## Next steps
* [Creating Automations](/docs/ona/automations/configure-automations): customize templates or build from scratch
* [Manual triggers](/docs/ona/automations/triggers/manual), [pull request triggers](/docs/ona/automations/triggers/pullrequest), and [scheduled triggers](/docs/ona/automations/triggers/timebased): configure when Automations run
* [Plans and limits](/docs/ona/automations/plans-and-limits): per-plan caps on Automations and actions
* [Guardrails](/docs/ona/automations/guardrails): control execution limits and blocked commands
* [Service accounts](/docs/ona/organizations/service-accounts): run Automations as a team identity
# Configure Automations
Source: https://ona.com/docs/ona/automations/configure-automations
Configure triggers, steps, guardrails, and workflows
This guide covers Automation configuration in detail. For a quick walkthrough, see [Create your first Automation](/docs/ona/create-first-automation).
Automations work best with [projects](/docs/ona/projects/overview). A project provides the Dev Container configuration, dependencies, and environment settings that your Automation runs against. We recommend setting up a project before creating Automations.
## Create an Automation
1. Navigate to **Automations** in the left panel.
2. Click **New**.
3. Choose **Start from scratch** or select a pre-configured template.
## Name and description
To set or change the name and description, open the **⋯** menu on the Automation and select **Rename**. A dialog opens where you can edit both fields.
## Trigger type
* **[Manual](/docs/ona/automations/triggers/manual)**: run on demand
* **[Pull request](/docs/ona/automations/triggers/pullrequest)**: trigger on PR events
* **[Scheduled](/docs/ona/automations/triggers/timebased)**: run on a schedule
Click the trigger node and then **Edit** to open the trigger configuration dialog.
## Runs on
Each trigger includes a **Runs on** setting that determines where the Automation runs:
| Scope | Description |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| **Projects** (recommended) | Run on specific [projects](/docs/ona/projects/overview). The Automation uses each project's Dev Container configuration and environment settings. |
| **Repositories** | Run on repositories matched by explicit URLs or a search query. Use for large-scale migrations across many repos. |
See [Manual triggers](/docs/ona/automations/triggers/manual) and [Pull request triggers](/docs/ona/automations/triggers/pullrequest) for scope configuration details per trigger type.
## Guardrails
Control execution limits to prevent Automations from running excessively:
* **Max concurrent actions**: simultaneous runs
* **Max total actions**: total allowed per run
Maximum values depend on your plan. See [Plans and limits](/docs/ona/automations/plans-and-limits) for per-plan caps and [Guardrails](/docs/ona/automations/guardrails) for details.
## Run Automation as
The **Run Automation as** selector is at the bottom of the trigger configuration dialog.
| Option | When to use |
| ---------------------------------------------------------- | -------------------------------------- |
| **Your user** | Manual workflows, personal Automations |
| **[Service account](/docs/ona/organizations/service-accounts)** | Scheduled or shared Automations |
Every user can run an Automation as themselves. Organization Admins and Automations Admins can also choose active service accounts. Automations cannot be configured to run as another human user.
## Steps
Steps execute in sequence within the same environment. Each step can access files, environment variables, and context from previous steps.
### Step types
| Type | Use when |
| ------------------------------------------ | ------------------------------------------------------------------------------------------- |
| **Prompt** | Flexible tasks requiring agent judgment: "analyze and improve", "update based on context" |
| **Command** | Deterministic operations: `npm test`, `docker build` |
| **Pull request** | Submit changes for review after making modifications |
| **[Report](/docs/ona/automations/report-step)** | Extract structured data from the execution: test coverage, dependency counts, build metrics |
### Example workflow
```
Step 1 (Prompt): "Upgrade all dependencies to their latest versions"
Step 2 (Command): npm test
Step 3 (PR): Create pull request with summary
```
**Guidance:**
* Use prompts for context-aware tasks that vary by repository.
* Use commands for predictable, repeatable operations.
* Combine both: commands for validation, prompts for intelligent changes.
## Add parameters to manual runs
Use Go template syntax in a **Prompt**, **Command**, or pull request title, description, or branch to request a value when someone starts the Automation manually.
For example, add `{{ .Parameters.ticket_id }}` to a prompt:
```text theme={null}
Investigate {{ .Parameters.ticket_id }}, implement a fix, and run the relevant tests.
```
The same syntax works in a shell command:
```bash theme={null}
./scripts/release.sh {{ .Parameters.release_channel }}
```
Parameter names must start with a letter or underscore and contain only letters, numbers, and underscores. An Automation can reference up to 10 unique parameters.
When a user clicks **Run**, Ona detects the referenced names and opens **Run with options**. Every value is required. See [Run an Automation with parameters](/docs/ona/automations/running-automations#run-with-parameters) for the execution flow.
Run parameters are entered interactively for manual executions. Scheduled and pull request triggers cannot prompt for parameter values, so use fixed values or trigger context for those runs.
Do not use run parameters for credentials or other sensitive values. Configure [service account secrets](/docs/ona/organizations/service-accounts#secrets) instead.
## Save and edit
Click **Save** to create the Automation. All settings can be modified after creation.
Pull request triggers require an event source: [GitHub](/docs/ona/integrations/configure-github) (for GitHub.com) or a [webhook](/docs/ona/automations/webhooks). See [Pull request triggers](/docs/ona/automations/triggers/pullrequest) for details.
## Enable and disable
Disable an Automation to stop it from running without deleting it. Disabled Automations keep their configuration, execution history, and triggers, but no new runs can start (manually or via triggers).
To toggle an Automation:
* **From the list**: open the three-dot menu on any Automation and select **Disable** or **Enable**.
* **From the details page**: use the toggle switch next to the Automation name.
Disabled Automations appear with muted styling in the list and show a "Disabled" status label. Use the **Enabled** / **Disabled** filter in the status dropdown to find them.
Disabling is useful when you want to pause a scheduled or event-driven Automation temporarily, for example during a code freeze or while debugging a failing workflow, without losing its configuration.
## Next steps
* [Run an Automation](/docs/ona/automations/running-automations)
* [Troubleshooting](/docs/ona/automations/troubleshooting)
# Automation guardrails
Source: https://ona.com/docs/ona/automations/guardrails
Safety controls and policies for Automations
Guardrails keep Automations running securely and within defined boundaries. For general Ona guardrails (policies, SSO, audit logs), see [Ona Guardrails](/docs/ona/guardrails/overview).
## Environment isolation
Each Automation runs in an isolated environment with dedicated resources. No access to other Automations or user environments. See [Environments](/docs/ona/environments/overview).
## Command deny lists
Prevent Automations from executing dangerous commands (`sudo`, `rm -rf /`, cloud CLIs). Blocked commands fail immediately. Configure at the organization level.
See [Command deny lists](/docs/ona/command-deny-list).
## Executable deny list
Block specific binaries from running inside Automation environments using kernel-level enforcement. Unlike command deny lists, executables are identified by content hash and cannot be bypassed by renaming.
See [Executable deny list](/docs/ona/organizations/policies/executable-deny-list).
## Audit logging
Every execution is logged: commands, file changes, PRs created, errors. Use for debugging and compliance.
See [Audit logs](/docs/ona/audit-logs/overview).
## Organization policy limits
Automation organization policy controls are in preview and available only to selected Enterprise organizations.
Organization administrators can configure Automation limits in **Settings → Agents → Policies → Automations**:
* **Automations per member** limits how many active Automations each member can own. The default is 5. Disabled Automations and Automations pending deletion do not count.
* **Projects per Automation** limits how many projects a member can select explicitly in one Automation.
* **Concurrent actions** limits how many actions an Automation can run at once.
The policy page shows the configured values and the Enterprise maximums: 50 Automations per member, 100 projects per Automation, and 25 concurrent actions.
Organization Admins and Automations Admins are exempt from organization-configured Automation limits. Plan and API maximums still apply.
Lowering the ownership limit does not modify existing Automations, but members at the limit cannot create or reactivate another Automation.
### Action limits
Control parallel execution to manage costs and prevent Automations from running excessively. Maximum values depend on your [plan](/docs/ona/automations/plans-and-limits).
| Limit | Core | Enterprise |
| -------------- | ---- | ---------- |
| Max concurrent | 10 | 25 |
| Max total | 50 | 100 |
Core plans enforce the caps listed above. Enterprise organizations can configure the concurrent-action policy up to the current system-wide ceiling of 25. The total-action limit remains subject to the system-wide ceiling of 100 actions per Automation. [Contact sales](https://ona.com/contact/sales) if you need higher limits.
Creating or updating an Automation with a concurrent-action value above the effective organization, plan, or API limit returns an error. Lowering the organization policy preserves existing Automation configuration, but the next action edit must comply with the current limit. Until then, new executions use the lower current limit. The same execution-time protection applies if a plan or API limit is reduced.
### Project limits
Enterprise organization admins can limit how many projects a member may select explicitly in one Automation, up to 100 projects. This limit applies to project contexts, not repository URL or repository search contexts.
Creating or updating an Automation with too many unique project IDs returns an error. Lowering the organization policy preserves existing Automation configuration, but the next project-context edit must comply with the current limit. An existing Automation that exceeds the current limit cannot start a new project-context execution until its project selection is updated.
### Per-execution time limit
Each execution action can have an optional maximum duration. When set, actions that exceed this time are stopped automatically. Configure this in the Automation's action limits.
### Queue behavior
When the concurrent limit is reached, additional actions queue and start as others complete. When the total limit is reached, the Automation stops. Increase limits and re-run to process remaining targets.
## Next steps
* [Command deny lists](/docs/ona/command-deny-list)
* [Executable deny list](/docs/ona/organizations/policies/executable-deny-list)
* [Audit logs](/docs/ona/audit-logs/overview)
* [Service accounts](/docs/ona/organizations/service-accounts)
# Background automations
Source: https://ona.com/docs/ona/automations/overview
Proactive background agents that combine AI prompts with deterministic commands in trigger-based, closed-loop workflows.
Automations are background agents that run in the cloud. They combine AI prompts with deterministic commands to deliver merge-ready pull requests triggered manually, on a schedule, on pull request events, or via webhooks.
Automations work best with [projects](/docs/ona/projects/overview). A project provides the Dev Container configuration, pre-installed dependencies, and environment settings that every Automation run uses. Set up a [project](/docs/ona/create-first-project) first, then build Automations on top of it.
## How Automations work
Every Automation follows a closed-loop workflow:
1. **Trigger**: run manually, on PR events, on a schedule, or via webhook.
2. **Execute**: Ona clones, branches, installs, builds, tests, iterates, commits, pushes, and opens a PR. The same loop a human engineer runs, except Automations can do it across hundreds of repos in parallel.
3. **Review**: inspect outputs, logs, and linked PRs. Approve and merge when satisfied.
Every Automation runs in a fully configured environment defined by `devcontainer.json` and `.ona/config.yaml`. Dependencies install, services start, tools are available. Not a minimal CI runner, but a full development environment.
For how Automations fit into the broader platform, see [Core Components](/docs/ona/understanding/core-components#automations).
## Runs in the cloud
Automations run in the background. Your laptop does not need to be on. Review results from your phone or iPad.
On Ona Cloud, execution happens in Ona's infrastructure. Enterprise customers can run Ona in their own network (AWS, GCP), giving Automations the same connectivity and context your engineers have: query databases, hit internal APIs, run the full test suite against staging without tunnels or exported secrets.
## Integrations
Ona has native integrations with [Linear](/docs/ona/integrations/configure-linear), [Sentry](/docs/ona/integrations/configure-sentry), [Notion](/docs/ona/integrations/configure-notion), [Granola](/docs/ona/integrations/configure-granola), [GitHub, GitLab, and Atlassian](/docs/ona/integrations/configure-atlassian), giving Automations the same context and permissions your engineers have to read backlogs, triage issues, and open PRs.
Any [MCP server](/docs/ona/mcp) can be added as config-in-code via `.ona/mcp-config.json` in your repository.
## Use cases
Get started with a template or [build your own from scratch](/docs/ona/automations/configure-automations).
See [Automations in practice](/docs/ona/automations/automations-in-practice) for detailed setup guides for each use case.
## Access
Automations are available on Core and Enterprise plans with [plan-based limits](/docs/ona/automations/plans-and-limits) on the number of Automations, concurrent actions, and features like webhooks. Enterprise organizations require [Ona Intelligence](https://ona.com/contact/sales); you can query its usage with the [Ona Intelligence usage API](/docs/ona/billing/ona-intelligence-usage-api).
Organization admins can [share Automations with individual users and groups](/docs/ona/automations/sharing-automations), allowing team members to run pre-built Automations without admin privileges.
## Related: Tasks and Services
Automations run across repositories at scale. For per-environment automation (database seeding, server startup, test commands), see [Tasks and Services](/docs/ona/configuration/tasks-and-services/overview). Tasks and Services are configured in `.ona/config.yaml` and run within individual environments.
## FAQ
No. Automation environments are isolated execution contexts, not interactive environments.
Test on one or a few repositories first. Review results, adjust steps, then scale up gradually.
**Projects**: repetitive tasks on known repositories, pull request triggers.
**Repositories**: large-scale migrations across thousands of repos, fine-grained selection.
Always in your Dev Container configuration. Packages are then available for all steps, pre-installed for faster runs.
Configure [MCP integrations](/docs/ona/mcp) in Settings > Integrations. These are then available to your Automations.
Yes. Disable it from the three-dot menu in the list or the toggle on the details page. Disabled Automations retain their configuration and history but won't start new runs. See [Enable and disable](/docs/ona/automations/configure-automations#enable-and-disable).
# Plans and limits
Source: https://ona.com/docs/ona/automations/plans-and-limits
Automation limits by organization plan
Automations are available on Core and Enterprise plans. Enterprise organizations must have [Ona Intelligence](https://ona.com/contact/sales) enabled to access Automations. To query Ona Intelligence usage programmatically, see the [Ona Intelligence usage API](/docs/ona/billing/ona-intelligence-usage-api).
Each plan has limits on the number of Automations, concurrent actions, and available features.
## Limits by plan
| Feature | Core | Enterprise |
| ---------------------------- | --------------------- | --------------------- |
| Total Automations | 50 | Unlimited |
| Max parallel actions | 10 | 25 |
| Max total actions | 50 | 100 |
| GitHub pull request triggers | | |
| Webhook event sources | - | |
| General Access sharing | | |
| Share with individual users | - | |
| Share with groups | - | |
Enterprise action limits are the current system-wide ceiling, not a plan cap. [Contact sales](https://ona.com/contact/sales) if you need higher limits.
## Automation count
Each organization can create up to the limit for its plan. Automations marked for deletion do not count toward the limit.
When you reach the limit, creating a new Automation returns an error. Delete unused Automations or [upgrade your plan](#upgrading) to increase the limit.
## Action limits
Action limits control how many repositories an Automation processes per run:
* **Max parallel**: simultaneous actions running at once
* **Max total**: total actions per Automation run
Both values must be positive integers (1 or greater).
These limits are set per Automation in the [guardrails configuration](/docs/ona/automations/guardrails). On Core plans, the values cannot exceed the caps listed above. Enterprise plans can use any value up to the current system-wide ceiling (25 parallel, 100 total). [Contact sales](https://ona.com/contact/sales) for higher limits.
## Webhooks
Webhook-based [pull request triggers](/docs/ona/automations/triggers/pullrequest) are available on the Enterprise plan. Core organizations can use GitHub.com pull request triggers through the [GitHub integration](/docs/ona/integrations/configure-github).
## Sharing
Both plans support sharing Automations with everyone in the organization via [General Access](/docs/ona/automations/sharing-automations).
Sharing with individual users and [groups](/docs/ona/organizations/groups) requires the Enterprise plan.
## Subscription management
To manage your Core subscription, visit **Settings > Billing**. For Enterprise features, [contact sales](https://ona.com/contact/sales).
# Report step
Source: https://ona.com/docs/ona/automations/report-step
Extract structured data from Automation executions
Report steps extract structured data from an Automation execution. Define the outputs you want (test coverage, dependency counts, build status), and the agent extracts them using prompts or shell commands. Results appear in a table with CSV export.
Use Report steps when you need to compare metrics across repositories or track values over time. Report results and the performance chart only appear for executions with more than one action. Single-action executions skip the report view.
## How it works
1. Earlier steps in the Automation do the work (run tests, scan dependencies, build).
2. The Report step defines **outputs** with typed schemas.
3. For each output, the agent extracts the value using a prompt or command.
4. Results display in a table on the execution summary page.
## Add a Report step
In the Automation editor, click **+** at the bottom of the step list and select **Report**.
## Configure outputs
Each output defines one value to extract. A Report step requires at least one output.
### Output fields
| Field | Required | Description |
| ----------------------- | -------- | -------------------------------------------------------------------------------------------------------------------- |
| **Title** | Yes | Display name shown in the results table (max 200 characters) |
| **Key** | Yes | Identifier in `snake_case` format, used for CSV export and the `add_agent_execution_result` tool (max 50 characters) |
| **Value type** | Yes | Data type for the output value |
| **Extraction method** | Yes | How to extract the value: prompt or command |
| **Acceptance criteria** | No | CEL expression that validates the extracted value |
### Value types
| Type | Constraints | Results display |
| ----------- | ----------------------- | ------------------------------------------------------------------- |
| **String** | Optional regex pattern | Plain text |
| **Integer** | Optional min/max bounds | Number, or progress bar when min and max are set |
| **Float** | Optional min/max bounds | Number (2 decimal places), or progress bar when min and max are set |
| **Boolean** | None | Green check or red cross badge |
When you set both min and max on a numeric type, the results table shows a color-coded progress bar: green above 80%, orange 50-80%, red below 50%.
### Extraction methods
**Prompt**: the agent reads the execution context and extracts the value based on your instructions. Use for values that require interpretation.
```
Extract the overall test coverage percentage from the test output
```
**Command**: a shell command that outputs the raw value. Use for values you can parse deterministically.
```bash theme={null}
grep -oP '\d+ passed' test-results.txt | grep -oP '\d+'
```
### Acceptance criteria
Optional [CEL expressions](https://github.com/google/cel-spec) that validate extracted values. The expression receives one variable (`value`) and must return a boolean.
Examples:
| Expression | Validates |
| ------------------------------------- | ------------------------------------- |
| `value >= 80` | Coverage is at least 80% |
| `value > 0` | At least one test passed |
| `value == true` | Build succeeded |
| `value.matches("^v[0-9]+\\.[0-9]+$")` | Version string matches semver pattern |
## View results
After execution, the results table appears on the execution summary page. Each row is one action (repository), and columns are the output keys you defined.
The report table and performance chart only appear for executions with multiple actions. If your Automation targets a single project or repository, the report step runs but results are not displayed in the summary view.
Click **Export CSV** to download the results as a spreadsheet for further analysis or reporting.
## Example: test coverage across repositories
This Automation runs tests across multiple repositories and reports coverage metrics.
**Step 1 (Prompt):**
```
Run the test suite with coverage enabled. Use the project's existing test
command. Save the output to test-results.txt.
```
**Step 2 (Report):**
| Output | Type | Extraction | Acceptance criteria |
| ------------- | ---------------- | --------------------------------------------------------------------------- | ------------------- |
| Test Coverage | Float (0-100) | Prompt: "Extract the overall test coverage percentage from the test output" | `value >= 80` |
| Tests Passed | Integer (min: 0) | Command: `grep -oP '\d+ passed' test-results.txt \| grep -oP '\d+'` | `value > 0` |
| Build Success | Boolean | Prompt: "Did the build complete successfully? Answer true or false." | None |
Schedule this on a weekly trigger to track coverage trends. Export CSV results to build dashboards or feed into other tools.
## Next steps
* [Create an Automation](/docs/ona/automations/configure-automations)
* [Run an Automation](/docs/ona/automations/running-automations)
* [Automations in practice](/docs/ona/automations/automations-in-practice)
# Running an Automation
Source: https://ona.com/docs/ona/automations/running-automations
Execute and monitor Automations
Running an Automation creates a run and one or more actions underneath it. Each action represents work on a specific target, such as a repository or project selected by the trigger configuration.
Use this page when you want to start an Automation manually, monitor progress, inspect failures, or review what the agent actually did.
## What a run contains
* **Run**: the top-level execution record
* **Actions**: per-target executions created under that run
* **Execution details**: action status, step progress, failures, and, when available, the full agent session for an action
## Start an Automation
Disabled Automations cannot be started. The **Run** button is hidden and triggers are ignored while an Automation is disabled. [Re-enable it](/docs/ona/automations/configure-automations#enable-and-disable) first.
1. Open the Automation (or use the three-dot menu from the list).
2. Click **Run** to start immediately with the Automation's configured targets when it has no parameters.
To change the targets for one execution, click the arrow next to **Run**, then select **Run with options**. Clicking **Run** opens the same dialog automatically when the Automation has no usable configured targets, uses an event-derived context, or references run parameters.
The dialog prevents the run from starting until it has at least one accessible project or a complete repository target. Projects you cannot access are removed from the execution target list.
## Run with parameters
When an Automation references parameters, **Run with options** lists every detected parameter. Enter a non-empty value for each one before clicking **Run**. Ona also validates required parameters on the server, so a manual run cannot start with unresolved templates through another client.
A parameter named `ticket_id`, for example, replaces `{{ .Parameters.ticket_id }}` in templated commands, prompts, and pull request fields. An Automation can reference up to 10 parameters.
```text theme={null}
Fix {{ .Parameters.ticket_id }} in {{ .Parameters.repository }}.
```
For this example, the dialog requires values for both `ticket_id` and `repository`. Spaces alone do not count as a value.
To define parameters in the Automation editor, see [Add parameters to manual runs](/docs/ona/automations/configure-automations#add-parameters-to-manual-runs).
Do not use parameters for sensitive values. Configure [service account secrets](/docs/ona/organizations/service-accounts#secrets) instead.
## Run with parameters through the API
Call `WorkflowService/StartWorkflow` with a [personal access token](/docs/ona/integrations/personal-access-token) or [service account token](/docs/ona/organizations/service-accounts). Put each template parameter in the `parameters` object.
```bash theme={null}
export ONA_API_URL="https://app.gitpod.io"
export GITPOD_API_KEY=""
curl "$ONA_API_URL/api/gitpod.v1.WorkflowService/StartWorkflow" \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"workflowId": "",
"parameters": {
"ticket_id": "ONA-123",
"repository": "gitpod-io/gitpod-next"
}
}'
```
This request uses the Automation's configured manual context. If the Automation has no manual trigger, Ona uses its scheduled trigger context. To choose targets for one run, add `contextOverride`:
```json theme={null}
{
"workflowId": "",
"contextOverride": {
"projects": {
"projectIds": [""]
}
},
"parameters": {
"ticket_id": "ONA-123"
}
}
```
The API applies the same rules as the UI:
* Every parameter referenced by a manual run must have a non-empty value. Spaces alone do not count.
* Parameter names must match `^[a-zA-Z_][a-zA-Z0-9_]*$`.
* A request can contain up to 10 parameters.
* `contextOverride` supports project, repository, and agent contexts. An event-derived `fromTrigger` context is not valid for a manual run.
* The caller must have access to every target in `contextOverride`.
If your organization uses a custom domain, set `ONA_API_URL` to that management-plane origin and use a token created on the same domain.
## Monitor progress
The run details page shows real-time execution status.
**Action statuses:**
* **Pending**: queued, waiting to start
* **Running**: currently executing
* **Done**: finished successfully
* **Failed**: finished with errors
* **Stopped**: canceled before completion
Click any action to inspect its steps, current state, and, when available, the full agent session.
## What to look for while monitoring
When a run is active, focus on:
* whether actions are starting as expected
* which step a failed action stopped on
* whether failures are isolated to one target or systemic across many targets
If many actions fail in the same place, the problem is usually in the Automation configuration, repository setup, or shared credentials. If only one action fails, the issue is usually specific to that target.
## Cancel execution
* **Single action**: three-dot menu > **Cancel**
* **Entire run**: click **Cancel** on the run details page
Running actions stop immediately. Pending actions are skipped.
## Review results
After completion:
* View execution summary (completed/failed/canceled actions, time)
* Click individual actions to review execution details
* Check your SCM for pull requests created by the Automation
## Execution history
View past runs from the Automation's **Execution History** section. Each run retains action status and execution details for later inspection.
For Enterprise organizations, agent details are available to anyone who can view the run. Codex runs show the effective model and reasoning effort; legacy Ona Agent runs show **Ona Agent**.
* **Organization admins** and **Automation admins** also see intelligence usage for each run.
* **Billing Viewers** see intelligence usage only for automation runs they already have permission to view.
* Other scoped organization roles do not see intelligence usage unless another assigned role grants one of these permissions.
After a run finishes and its final usage has been calculated, managed usage is shown in credits and bring-your-own-key usage is shown in your organization's billing currency. If any bring-your-own-key prices are missing, the run shows its token usage instead of a partial cost. An organization admin can add model pricing under **Cost & Budgets**.
Use history to compare configuration changes over time or to confirm whether a failure started after a workflow, secret, or trigger change.
## Common follow-ups
After reviewing a run, the next step is usually one of:
* update the Automation configuration and run it again
* fix repository setup or secrets for the failing target
* tighten [guardrails](/docs/ona/automations/guardrails) or switch to a [service account](/docs/ona/organizations/service-accounts)
* move from manual testing to a [time-based](/docs/ona/automations/triggers/timebased) or [pull request](/docs/ona/automations/triggers/pullrequest) trigger
## Next steps
* [Guardrails](/docs/ona/automations/guardrails)
* [Service accounts](/docs/ona/organizations/service-accounts)
* [Troubleshooting](/docs/ona/automations/troubleshooting)
# Sharing Automations
Source: https://ona.com/docs/ona/automations/sharing-automations
Share Automations with individual users, groups, or your entire organization
Share Automations so team members can run pre-built Automations without needing to create their own.
Only **organization admins** can share Automations. Having the Admin role on a single Automation is not enough.
To give a team admin access to **all** Automations in the organization, assign the [Automations Admin](/docs/ona/organizations/organization-roles) role to their group instead of sharing Automations individually.
Sharing capabilities depend on your plan:
| Sharing method | Core | Enterprise |
| -------------------------------- | --------------------- | --------------------- |
| General Access (everyone in org) | | |
| Individual users | - | |
| Groups | - | |
## Roles
When sharing an Automation, you assign a role that controls what the recipient can do:
| Role | Permissions |
| ------------ | --------------------------------------------------------------- |
| **Admin** | Full control: edit, delete, share, run, and view all executions |
| **Executor** | Run the Automation and view their own executions |
| **Viewer** | View the Automation and execution history (read-only) |
## Share with everyone (General Access)
Available on Core and Enterprise plans.
Use the **General Access** toggle to share an Automation with all members of your organization:
1. Open the Automation and click **Share**.
2. In the **General Access** section, select **Everyone in **.
All organization members receive Executor access. Toggle back to **Only groups and users with access** to revoke org-wide access.
## Share with individual users
Available on the [Enterprise plan](/docs/ona/automations/plans-and-limits).
1. Open the Automation and click **Share**.
2. Search for and select users to add.
3. Choose a role for each user.
## Share with groups
Available on the [Enterprise plan](/docs/ona/automations/plans-and-limits). [Custom groups](/docs/ona/organizations/groups) must be configured first.
1. Open the Automation and click **Share**.
2. Select groups to add.
3. Choose a role for the group.
## Remove access
1. Click **Share**, find the user or group, click the role dropdown, and select **Remove access**.
Removed users and groups immediately lose access. Past executions remain visible to admins.
## For Automations shared with users
Automations that are shared with a user appear in their **Automations** list. Depending on their role, they can run or view them on any project or repository you have access to.
Automations run under **your identity**. Commits and PRs are attributed to your account, using your SCM permissions.
## Next steps
* [Create Automations](/docs/ona/automations/configure-automations)
* [Manage groups](/docs/ona/organizations/groups)
* [Plans and limits](/docs/ona/automations/plans-and-limits)
* [Troubleshooting](/docs/ona/automations/troubleshooting)
# Manual triggers
Source: https://ona.com/docs/ona/automations/triggers/manual
Run Automations on demand
Manual triggers run when you explicitly start them. Use them for one-time migrations, testing Automations before scheduling, or changes that need human judgment on timing.
They are the safest way to develop a new Automation because you control exactly when it starts and can review the results before making it recurring or event-driven.
## When to use manual triggers
Manual triggers are a good fit for:
* trying a new Automation on a small set of targets
* maintenance work you want to supervise closely
* one-off repository sweeps
* workflows that should only run after a human decision
## Configuration
### Runs on
#### Projects (recommended)
Select one or more [projects](/docs/ona/projects/overview). The Automation runs on all repositories within them. Best for repetitive tasks on known repositories.
#### Repositories
Use a search query to filter repositories. Best for large-scale migrations across many targets.
| Query | Matches |
| ----------- | ------------------------------------------- |
| `backend` | Repositories with "backend" in name |
| `frontend-` | Repositories starting with "frontend-" |
| `myorg/` | All repositories under "myorg" organization |
Partial matches work across owner and repository names.
**Search syntax:** [GitHub](https://docs.github.com/en/search-github/searching-on-github/searching-for-repositories) | [GitLab](https://docs.gitlab.com/ee/user/search/)
## Choosing projects vs repository queries
* **Projects** are best when you already know the exact repositories and want them to use project-level configuration.
* **Repository queries** are best when you want to sweep a broader set of repositories without manually listing them.
If the workflow depends on project-specific configuration and access, prefer projects.
## Running
1. Navigate to **Automations**
2. Click your Automation
3. Click **Run** to use its configured targets, or use the arrow next to **Run** and select **Run with options** to change targets or enter parameter values.
If the Automation references parameters or has no usable configured targets, clicking **Run** opens **Run with options** automatically. You must provide every parameter and at least one valid target before the execution can start.
The Automation creates actions for the selected targets, which you can then monitor from the execution view. See [Running an Automation](/docs/ona/automations/running-automations) for parameter syntax and target validation behavior.
## Review after the run
After a manual run, check:
* which targets were selected
* whether the right repositories were included
* whether the actions produced the expected pull requests, comments, or reports
If the run looks good, the next step is often to convert the same workflow into a [time-based trigger](/docs/ona/automations/triggers/timebased) or a [pull request trigger](/docs/ona/automations/triggers/pullrequest).
## Next steps
* [Run an Automation](/docs/ona/automations/running-automations)
* [Pull request triggers](/docs/ona/automations/triggers/pullrequest)
* [Time-based triggers](/docs/ona/automations/triggers/timebased)
# Pull request triggers
Source: https://ona.com/docs/ona/automations/triggers/pullrequest
Trigger Automations from pull request events
Pull request triggers run Automations when PR events occur: code changes, reviews, merges. Use them for automated code review, security scanning, documentation updates, and compliance checks. They support **GitHub.com** through the GitHub App, and **GitLab** and **Bitbucket Cloud** through webhooks. Use a [service account](/docs/ona/organizations/service-accounts) to separate Automation activity from human work.
## Configuration
### Event source
Pull request triggers need an event source that delivers PR events from your Git provider to Ona. There are two options:
| Source | When to use |
| ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **[GitHub](/docs/ona/integrations/configure-github)** | You use GitHub.com and have the [GitHub integration](/docs/ona/integrations/configure-github) enabled. No extra setup is required. Ona receives PR events through the App. |
| **[Webhook](/docs/ona/automations/webhooks)** | You use GitLab or Bitbucket Cloud, or you prefer not to enable the GitHub integration. You create a webhook in Ona and register it in your Git provider. |
#### GitHub
If your organization has the [GitHub integration](/docs/ona/integrations/configure-github) enabled, select **GitHub** as the event source. Ona receives PR events directly through the App.
When your Ona organization connects more than one GitHub organization, each event source includes the GitHub organization name, such as `github.com/acme`. Select the organization that owns the repositories this Automation should monitor.
#### Webhook
If your organization has [webhooks](/docs/ona/automations/webhooks) configured, a dropdown appears instead, letting you select an existing webhook or configure a new one.
### Runs on
* **Projects** (recommended): select projects. The Automation monitors all repositories within them.
* **Repositories**: use a search query to filter specific repositories.
### Triggers on PR
| Event | When it fires |
| ---------------- | ---------------------------- |
| Opened | New PR created |
| Updated | New commits pushed |
| Ready for review | Draft marked ready |
| Review requested | Reviewer assigned for review |
| Approved | Reviewer approves |
| Merged | PR merged |
| Closed | PR closed without merge |
**Common combinations:** Opened + Updated (check every change), Ready for review (analysis before human review), Approved (final validation)
## Next steps
* [GitHub](/docs/ona/integrations/configure-github): enable the GitHub integration for webhook-free PR triggers
* [Webhooks](/docs/ona/automations/webhooks): create and manage webhook endpoints
* [Run an Automation](/docs/ona/automations/running-automations)
* [Manual triggers](/docs/ona/automations/triggers/manual)
* [Time-based triggers](/docs/ona/automations/triggers/timebased)
# Time-based triggers
Source: https://ona.com/docs/ona/automations/triggers/timebased
Schedule Automations on a recurring basis
Time-based triggers run Automations on a schedule: dependency updates, security scans, compliance checks, nightly builds.
Use them when the work should happen predictably without someone clicking **Run** each time.
## Good fits for scheduled runs
* nightly validation and cleanup
* weekly dependency maintenance
* regular backlog triage
* periodic reporting or compliance checks
## Configuration
### Runs on
* **Projects** (recommended): select projects. Runs on all repositories within them.
* **Repositories**: use a search query (see [manual triggers](/docs/ona/automations/triggers/manual#repositories) for examples).
### Schedule
| Frequency | Options |
| --------- | ----------------------------------------- |
| Hourly | Minute (0-59) |
| Daily | Hour, minute. Runs every day. |
| Weekdays | Hour, minute. Runs Monday through Friday. |
| Weekly | Day of week, hour, minute |
| Monthly | Day of month, hour, minute |
**Examples:**
* Weekly dependency updates: every Monday at 2 AM UTC
* Weekday backlog triage: every weekday at 9 AM UTC
* Nightly security scans: every day at 1 AM UTC
* Monthly compliance: first day of the month at midnight UTC
## Timezone
Schedules are evaluated in UTC. Weekday schedules run Monday through Friday in UTC, so keep timezone differences in mind when choosing times for teams that work in other timezones.
## Scheduling tips
* Run outside peak working hours when the workflow is resource-intensive.
* Leave enough time for one run to finish before the next one begins.
* Start with a narrower target set before scheduling the Automation broadly.
* Pair scheduled runs with [service accounts](/docs/ona/organizations/service-accounts) when you want stable credentials independent of an individual user.
## After you enable the trigger
Once saved, the Automation waits for the next matching schedule window. Review the first few runs in [Execution History](/docs/ona/automations/running-automations#execution-history) to confirm the cadence and targets are correct.
## Next steps
* [Run an Automation](/docs/ona/automations/running-automations)
* [Manual triggers](/docs/ona/automations/triggers/manual)
* [Pull request triggers](/docs/ona/automations/triggers/pullrequest)
# Troubleshooting automations
Source: https://ona.com/docs/ona/automations/troubleshooting
Common Automation issues and solutions
## Debugging failed executions
1. Open the failed execution from the Automation details page.
2. Review the **Action session** for error messages.
3. Check which step failed and review output.
## Trigger issues
### Manual triggers not starting
* Verify account has access to target repositories/projects.
* Check repositories match your search query.
* Verify permissions to run Automations.
### Pull request triggers not firing
* Verify webhook configured correctly in GitHub/GitLab.
* Check webhook secret matches Automation settings.
* Confirm PR events are selected in webhook config.
See [Pull request triggers](/docs/ona/automations/triggers/pullrequest).
### Time-based triggers not running
* Verify schedule is correct (schedules run on UTC).
* Check the Automation is not paused or disabled.
* Confirm service account has repository access.
See [Time-based triggers](/docs/ona/automations/triggers/timebased).
## Repository access errors
"Repository not found" or "access denied":
| Account type | Check |
| --------------- | ------------------------------------------------ |
| User | SCM access? PAT scopes? Repo still exists? |
| Service account | Git auth configured? PAT valid? Required scopes? |
See [Service accounts](/docs/ona/organizations/service-accounts).
## Permission errors
"Permission denied" or "Insufficient permissions":
* Projects must be shared with "all members" for Automations to access them.
* Verify service account is organization member with SCM permissions.
See [Project sharing](/docs/ona/projects/project-sharing).
## Sharing issues
### Cannot see the Automations page
Core and Enterprise organization members can open Automations even when no Automation has been shared with them. Members who cannot create Automations and do not have shared access see the education screen, where they can find an Organization Admin. If the Automations link is missing, check the organization's [plan](/docs/ona/automations/plans-and-limits).
### "Project not found" on shared Automation
The Automation targets a project you do not have access to. Ask admin to share the project, or select a different target.
### Git auth errors on shared Automations
Shared Automations run under your identity. Re-authenticate at [app.ona.com](https://app.ona.com) > **Settings** > **Git Providers**.
### Cannot see other users' executions
Expected. Executors only see their own executions. Admins see all.
## Plan limits
### "Your plan allows a maximum of N automations"
Your organization has reached the maximum number of Automations for its plan. Delete unused Automations or upgrade your plan. See [Plans and limits](/docs/ona/automations/plans-and-limits).
### "The maximum concurrent actions limit cannot exceed N on your current plan"
The max parallel value you set exceeds your plan's cap. Reduce the value or upgrade your plan. See [Guardrails](/docs/ona/automations/guardrails) for per-plan limits.
### "The maximum total actions limit cannot exceed N on your current plan"
The max total value you set exceeds your plan's cap. Reduce the value or upgrade your plan. See [Guardrails](/docs/ona/automations/guardrails) for per-plan limits.
### "Organizations on the ... tier cannot create webhooks"
Webhook creation is restricted to the Enterprise plan. Non-enterprise organizations can use manual and time-based triggers. See [Pull request triggers](/docs/ona/automations/triggers/pullrequest).
## Getting help
Contact your Ona account manager with:
* Automation name/ID and execution ID.
* Error messages from Action session.
* Steps to reproduce.
# Webhooks
Source: https://ona.com/docs/ona/automations/webhooks
Receive SCM events to trigger Automations
Webhooks are standalone endpoints that receive events from your Git provider (GitHub, GitLab, or Bitbucket Cloud). Once created, a webhook can be shared across multiple Automations. You configure the connection to your SCM once and reuse it wherever you need pull request triggers.
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
## How webhooks work
1. You create a webhook in Ona, choosing a provider (GitHub, GitLab, or Bitbucket Cloud) and a scope (repository or organization). The scope can be configured later, but the webhook won't process events until one is set.
2. Ona generates a **payload URL** and a **secret token**.
3. You register the payload URL and secret in your Git provider's webhook settings.
4. When PR events occur, the Git provider sends a signed payload to Ona.
5. Ona verifies the signature, matches the event to bound Automations, and triggers them.
A single webhook can be bound to multiple Automations.
## Scope types
| Type | Description |
| ---------------- | ------------------------------------------------------------------------------------------------------------ |
| **Repository** | Scoped to one or more specific repositories. Events from other repositories are ignored. |
| **Organization** | Scoped to an entire SCM organization or group. Events from any repository in that organization are accepted. |
Repository-scoped webhooks support up to 100 repositories per webhook.
## Required permissions
Only **organization admins** can create, update, and delete webhooks. The Automations Admin role does not currently grant webhook management permissions.
Organization members can view webhooks but cannot modify them.
## Creating a webhook
### Dashboard
1. Go to **Automations** and click **Webhooks** in the top bar.
2. Click **+ Webhook** to open the creation dialog.
3. Select the **location** (GitHub, GitLab, or Bitbucket Cloud).
4. Choose the **type** (Organization or Repository).
5. Enter a **name** for the webhook.
6. Click **Create Webhook**.
After creation, Ona shows the **webhook configuration** dialog with the **payload URL** and **secret token**. Select the scope: the specific repositories or organization this webhook should accept events from.
Scope configuration is optional during creation. Set it later from the webhook details panel. The webhook shows a "Setup incomplete" badge until a scope is configured.
### CLI
```bash theme={null}
# Repository webhook for a single repo
ona webhook create \
--name "My Webhook" \
--type repository \
--scope "owner/repo" \
--provider github
# Repository webhook for multiple repos
ona webhook create \
--name "Multi Webhook" \
--type repository \
--scope "owner/repo1" \
--scope "owner/repo2" \
--provider github
# Organization webhook
ona webhook create \
--name "Org Webhook" \
--type organization \
--organization-scope "my-org" \
--provider gitlab
```
The CLI returns the webhook ID and payload URL but not the secret. To retrieve the secret token, run:
```bash theme={null}
ona webhook secret get
```
Once you have both values, register them in your Git provider as described in the next section.
## Registering the webhook in your Git provider
After creating the webhook in Ona, register it in your Git provider so events are delivered.
### GitHub
1. Go to `https://github.com///settings/hooks` and click **Add webhook**.
2. Enter the **Payload URL** from Ona.
3. Enter the **Secret** from Ona.
4. Set **Content type** to `application/json`.
5. Select **Let me select individual events** and check **Pull requests**.
6. Click **Add webhook**.
1. Go to `https://github.com/organizations//settings/hooks` and click **Add webhook**.
2. Enter the **Payload URL** from Ona.
3. Enter the **Secret** from Ona.
4. Set **Content type** to `application/json`.
5. Select **Let me select individual events** and check **Pull requests**.
6. Click **Add webhook**.
[GitHub webhook documentation](https://docs.github.com/en/webhooks/using-webhooks/creating-webhooks)
### GitLab
1. Go to `https://gitlab.com///-/hooks` and click **Add new webhook**.
2. Enter the **URL** (payload URL from Ona).
3. Enter the **Secret token** from Ona.
4. Check **Merge request events**.
5. Click **Add webhook**.
1. Go to `https://gitlab.com/groups//-/hooks` and click **Add new webhook**.
2. Enter the **URL** (payload URL from Ona).
3. Enter the **Secret token** from Ona.
4. Check **Merge request events**.
5. Click **Add webhook**.
[GitLab webhook documentation](https://docs.gitlab.com/ee/user/project/integrations/webhooks.html)
### Bitbucket Cloud
1. Go to `https://bitbucket.org///admin/webhooks` and click **Add webhook**.
2. Enter the **URL** (payload URL from Ona).
3. Enter the **Secret** from Ona.
4. Under **Triggers**, select **Choose from a full list of triggers** and check **Pull Request: Created**, **Updated**, **Approved**, **Merged**, **Declined**.
5. Click **Save**.
1. Go to `https://bitbucket.org//workspace/settings/webhooks` and click **Add webhook**.
2. Enter the **URL** (payload URL from Ona).
3. Enter the **Secret** from Ona.
4. Under **Triggers**, select **Choose from a full list of triggers** and check **Pull Request: Created**, **Updated**, **Approved**, **Merged**, **Declined**.
5. Click **Save**.
[Bitbucket webhook documentation](https://support.atlassian.com/bitbucket-cloud/docs/manage-webhooks/)
## Managing webhooks
### Viewing webhook details
Click any webhook in the list to open its details panel. The panel shows:
* Webhook name
* Payload URL and secret token (copyable)
* Provider and scope configuration
### Updating scope
Change the repositories or organization a webhook is scoped to at any time from the details panel. The provider and type cannot be changed after creation. Create a new webhook instead.
### Rotating the secret
If a webhook secret is compromised, rotate it from the details panel. After rotation:
1. Copy the new secret from Ona.
2. Update the secret in your Git provider's webhook settings.
The old secret is immediately invalidated.
### Deleting a webhook
When you delete a webhook:
* Any Automations bound to it have their pull request triggers converted to **manual** triggers. They stop receiving PR events but can still be run manually.
* Running executions continue until they complete.
* The webhook is removed from Ona but **not** from your Git provider. Remove it from your provider's settings separately to stop sending events.
## Binding webhooks to Automations
When configuring a [pull request trigger](/docs/ona/automations/triggers/pullrequest) on an Automation, select a webhook from the dropdown or create a new one inline from the trigger configuration.
Multiple Automations can share the same webhook. Each Automation independently defines which PR events it responds to (opened, updated, merged, etc.).
## Security
Webhooks authenticate using HMAC signature verification. When your Git provider sends an event, it signs the payload using the shared secret. Ona verifies the signature before processing the event. Events with invalid signatures are rejected.
Keep your webhook secret secure. If compromised, [rotate it](#rotating-the-secret) immediately.
## Next steps
* [Pull request triggers](/docs/ona/automations/triggers/pullrequest): configure which PR events trigger your Automations
* [Creating Automations](/docs/ona/automations/configure-automations): set up Automations that use webhooks
* [Plans and limits](/docs/ona/automations/plans-and-limits): webhook availability by plan
# Bash commands
Source: https://ona.com/docs/ona/bash-commands
Run bash commands in sessions using the ! prefix
Prefix any command with `!` to run it immediately and share the output with the agent. The output becomes part of the session context, so the agent can reference it in responses.
```
!git status
!npm test
!cat src/config.js
```
## What happens when you use `!`
`!` is the fastest way to bring shell output into the conversation without asking the agent to decide which command to run.
When you run a command this way:
* the output becomes part of the chat context for the current session
* the command result is shown directly in the session
* you can immediately ask follow-up questions about the result
## When to use ! commands
Use `!` when you want to share specific output with the agent:
* **Share errors for debugging**: `!npm test` then ask "why is this failing?"
* **Provide context**: `!cat package.json` before asking about dependencies
* **Verify state**: `!git branch` before asking about branching strategy
For complex multi-step operations, code changes, or open-ended analysis, ask the agent directly and let it run commands as needed.
## Good fits vs bad fits
Good fits:
* a single diagnostic command
* a one-off log or file dump
* a test run whose output you want the agent to interpret
Less good fits:
* long investigative workflows
* commands that mutate the repo in ways you want the agent to manage
* repeated shell sequences better handled by the agent itself or by an Automation
## Tips
* Use short, targeted commands so the output stays readable in chat.
* Prefer `!git status` or `!pytest -q` over huge recursive dumps.
* If the output is noisy, run a narrower command and ask a more specific follow-up question.
# Set up your first environment
Source: https://ona.com/docs/ona/configuration/devcontainer/getting-started
Create a Dev Container so your environments and agents have everything they need.
Add a Dev Container to your repository so every environment, whether started by a teammate or an agent, launches with the right runtimes, tools, and services already running.
* **Agents** get a reproducible environment to execute commands, run tests, and iterate
* **New team members** start an environment and immediately have everything they need
* **Everyone** works in the same setup, no more "it works on my machine"
A Dev Container can include language runtimes, databases, tools, editor extensions, environment variables, and startup tasks.
## Create your first Dev Container
Create a `.devcontainer/devcontainer.json` file in your repository:
```json theme={null}
{
"name": "My Project",
"image": "mcr.microsoft.com/devcontainers/javascript-node:20",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": { "moby": false }
},
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
},
"postCreateCommand": "npm install"
}
```
This gives you:
* Node.js 20 with npm
* Docker available inside the environment
* ESLint and Prettier extensions
* Dependencies installed automatically
Start an environment from your repository. Ona builds the container and you're ready to code.
## Run tasks on startup
For more control over startup behavior, use [Tasks & Services](/docs/ona/configuration/tasks-and-services/overview):
```yaml theme={null}
# .ona/config.yaml
tasks:
install:
name: Install dependencies
command: npm install
triggeredBy:
- postDevcontainerStart
services:
database:
name: PostgreSQL
commands:
start: docker run --rm -t --name database -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres:15
ready: docker exec database pg_isready
stop: docker stop database
triggeredBy:
- postEnvironmentStart
```
Now every environment starts with dependencies installed and a database running.
## Verify it works
Once your environment starts, verify the setup. These examples assume a Node.js project. Substitute your own project's commands:
```bash theme={null}
# Check your runtime
node --version
# Run your tests (if your project has a test script)
npm test
# Start your dev server (if your project has a dev script)
npm run dev
```
If your project's commands work inside the environment, your Dev Container is ready. Agents will be able to run the same commands reliably.
## Next steps
* [Optimize startup times](/docs/ona/configuration/devcontainer/optimizing-startup-times) with prebuilds and image caching
* [Dev Container reference](/docs/ona/configuration/devcontainer/overview) for advanced configuration: multi-container setups, private images, elevated privileges
* [Teach agents your codebase](/docs/ona/agents-md) so they understand your conventions
# Optimize startup times
Source: https://ona.com/docs/ona/configuration/devcontainer/optimizing-startup-times
Fast startup times enable humans and agents to work effectively and autonomously across multiple tasks in parallel.
Optimized environments start in 1-3 minutes. Without optimization, startup can take 10+ minutes. This page covers the strategies that close that gap.
## Optimization strategies
### Use prebuilds
[Prebuilds](/docs/ona/projects/prebuilds) run your environment setup ahead of time: container builds, dependency installation, and startup tasks. When an environment starts, it loads from a prebuild snapshot instead of running setup from scratch.
This is the single biggest optimization. Configure prebuilds to run on a daily schedule before your team or agents start work. You can also run a prebuild manually after important dependency or setup changes.
### Enable Dev Container image caching
For runners in your VPC, enable image caching to avoid rebuilding containers:
* **[AWS runners](/docs/ona/runners/devcontainer-image-cache#aws-runners)**: Caches built Dev Container images automatically
* **[GCP runners](/docs/ona/runners/devcontainer-image-cache#gcp-runners)**: Supports image caching through Artifact Registry
[Ona Cloud](/docs/ona/runners/ona-cloud) includes image caching by default.
### Let Ona maintain base snapshots on AWS runners
For eligible Enterprise AWS runners, Ona automatically maintains [base snapshots](/docs/ona/runners/aws/base-snapshots) from the organization default image. Base snapshots preload container image layers and shared startup assets before an environment starts. No project or developer configuration is required.
Base snapshots complement prebuilds and the Dev Container image cache. A project prebuild takes precedence when one is available.
### Optimize your Dockerfile
Structure your Dockerfile for caching efficiency:
* **Put stable dependencies first**: System packages, build tools, and runtimes that rarely change should be early in the Dockerfile.
* **Put volatile dependencies last**: Application dependencies that change frequently go at the end.
* **Use prebuilt base images**: Push your base image to a registry and reference it in `devcontainer.json`.
### Use tasks for dynamic setup
For setup that must happen at runtime (database seeding, environment-specific config), use [Tasks](/docs/ona/configuration/tasks-and-services/overview) rather than baking everything into the image.
## Use one environment per task
Create a fresh environment for each piece of work rather than reusing environments across tasks. This matches how agents operate:
1. Agent receives a task
2. Agent starts a clean environment
3. Agent completes the work and creates a PR
4. Environment is discarded
This isolation gives you:
* **No state conflicts**: Each task gets a clean slate
* **Parallel execution**: Multiple agents work simultaneously without interference
* **Mistakes are free**: If something goes wrong, discard the environment and start fresh
With the optimizations above, startup stays under a few minutes.
## Measure startup time
Track these metrics to identify bottlenecks:
* **Container build time**: How long does the Dev Container image take to build?
* **Dependency installation**: How long do startup tasks take to run?
* **Prebuild freshness**: Are prebuilds running often enough to stay current?
If environments take more than 3 minutes to start, check your prebuild configuration first.
# Container configuration
Source: https://ona.com/docs/ona/configuration/devcontainer/overview
Standardize development environments across your team with Dev Container configuration.
Ona fully supports [Development Containers](https://containers.dev/). Define your setup in a `devcontainer.json` file to get standardized, version-controlled environments with consistent tooling across your team, whether single-container or multi-container, with VS Code and JetBrains support.
For how environments and Dev Containers fit into the broader platform, see [Core Components](/docs/ona/understanding/core-components#environments).
## Configuration
### File Location
Place your `devcontainer.json` file in one of these standard locations:
* `.devcontainer/devcontainer.json`
* `.devcontainer.json`
### Basic Configuration Example
```json theme={null}
{
"name": "My Project",
"image": "mcr.microsoft.com/devcontainers/universal:4.0.1-noble",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": { "moby": false }
},
"customizations": {
"vscode": {
"extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"],
"settings": {
"editor.formatOnSave": true
}
},
"jetbrains": {
"plugins": ["com.wix.eslint", "intellij.prettierJS"]
}
},
"forwardPorts": [3000, 8080]
}
```
This configuration:
* Uses the Universal image with common languages and tools pre-installed (Node.js, Python, Go, Java, and more)
* Adds Docker-in-Docker support
* Includes ESLint and Prettier VS Code extensions
* Installs the ESLint & PrettierJS plugin for JetBrains IDEs
* Configures auto-formatting on save
* Declares ports 3000 and 8080 for [IDE-managed forwarding](#forward-ports)
### Forward ports
Use `forwardPorts` in `devcontainer.json` to tell supported IDEs which ports to forward from the Dev Container to `localhost` on your local machine. As the port-forwarding is performed by your IDE the ports are not accessible to anyone else. If you need a shareable URL or want to access a port in the environment without using an IDE, use Ona [Port sharing](https://ona.com/docs/ona/integrations/ports#port-sharing).
See the official [Dev Container JSON reference](https://containers.dev/implementors/json_reference/#general-properties) for more details about port-related properties.
## Multiple Dev Container configurations
You can manage multiple Dev Container configurations using Ona projects. This allows you to define different environments for:
* Different branches or repositories
* Various development scenarios
* Specialized tasks requiring specific tools
## Known limitations
When using Dev Containers with Ona, be aware of these limitations:
* Conflicting features can cause build failures (Ona will display an error message)
* Some Dev Container commands might behave differently in Ona's environment
* When build or startup errors occur, [recovery mode](#recovery-mode) is engaged, requiring manual intervention
## Recommended images
Microsoft provides well-maintained Dev Container base images for popular development stacks:
* `mcr.microsoft.com/devcontainers/universal:4.0.1-noble` - Full-featured image with common languages and tools
* `mcr.microsoft.com/devcontainers/javascript-node` - Node.js development
* `mcr.microsoft.com/devcontainers/python` - Python development
* `mcr.microsoft.com/devcontainers/dotnet` - .NET development
* `mcr.microsoft.com/devcontainers/java` - Java development
* `mcr.microsoft.com/devcontainers/go` - Go development
* `mcr.microsoft.com/devcontainers/base:2.0.4-noble` - Minimal image
## Advanced configuration
### Using secrets during builds
[Organization](/docs/ona/organizations/organization-secrets) and [project](/docs/ona/projects/project-secrets) secrets can be used during Dev Container image builds via [secret mounts](https://docs.docker.com/build/building/secrets/#secret-mounts). This is useful when your Dockerfile needs to authenticate with private package registries, pull licensed dependencies, or access credentials that should not be baked into the final image.
Secrets are not exposed by default. Each `RUN` instruction in your Dockerfile must explicitly request the secrets it needs using the `--mount=type=secret` flag. The mounted secret itself is only available for the duration of that `RUN` step and is not included in the image layer.
The secret mount is ephemeral, but commands within the `RUN` step can still write secret values to files or configuration stores that **are** persisted in the image. If you don't want a credential to be available in the resulting image, avoid commands like `npm config set` that write credentials to disk. Use the `env=` mount pattern or clean up any written files before the `RUN` step ends.
User secrets are not available during builds. Built images are cached and shared across the project when the [Dev Container image cache](/docs/ona/runners/devcontainer-image-cache) is enabled, so personal credentials in a build could be exposed to other team members.
Build-time secret mounts require a Dockerfile-based Dev Container (`build.dockerfile` or `dockerFile` in `devcontainer.json`). Docker Compose-based Dev Containers are not yet supported.
#### How to reference a secret
The `id` in `--mount=type=secret,id=...` must match how the secret is configured in Ona. For file secrets, the `id` is the full file path. For environment variable secrets, the `id` is the variable name.
Use `target=` to control where the secret is mounted during the `RUN` step. The `target` path can be any location your build step needs. It does not have to match the `id`.
#### Example: private npm registry (file mount)
Given a file secret configured in Ona at `/usr/local/secrets/npm-token`:
```dockerfile theme={null}
FROM node:20
COPY package.json package-lock.json ./
RUN --mount=type=secret,id=/usr/local/secrets/npm-token,target=/tmp/npm-token \
echo "//registry.npmjs.org/:_authToken=$(cat /tmp/npm-token)" > .npmrc && \
npm ci && \
rm -f .npmrc
```
The `.npmrc` file is written, used for `npm ci`, and removed within the same `RUN` step so the token is not persisted in the image layer.
#### Example: private npm registry (env mount)
The `env=` option mounts the secret directly as an environment variable, avoiding the need to read from a file. This requires Dockerfile syntax v1.10.0+, so you must add `# syntax=docker/dockerfile:1` as the very first line of your Dockerfile (before any other instructions or comments):
```dockerfile theme={null}
# syntax=docker/dockerfile:1
FROM node:20
COPY package.json package-lock.json ./
RUN --mount=type=secret,id=NPM_TOKEN,env=NPM_TOKEN \
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc && \
npm ci && \
rm -f .npmrc
```
The `# syntax=docker/dockerfile:1` directive pulls the `docker/dockerfile:1` image from Docker Hub to use as the build frontend. If your environment restricts access to Docker Hub, you can mirror the image to a private registry and reference it instead:
```dockerfile theme={null}
# syntax=my-registry.example.com/docker/dockerfile:1
```
No changes to `devcontainer.json` are needed. Ona passes the secrets to the build process, and your Dockerfile controls which `RUN` steps can access them.
### Multi-Container Development
For more complex setups, you can define multiple containers using Docker Compose.
**devcontainer.json:**
```json theme={null}
{
"name": "Multi-container App",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"customizations": {
"vscode": {
"extensions": ["ms-azuretools.vscode-docker"]
}
}
}
```
**docker-compose.yml:**
```yaml theme={null}
version: "3.8"
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- ..:/workspace:cached
network_mode: host
command: sleep infinity
db:
image: postgres:16-alpine
restart: unless-stopped
network_mode: host
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: app_dev
```
**Required:** Set `network_mode: host` on all services. Without this, services attempt to bridge networks, which can lock you out of your dev container with no way to recover except deleting the environment.
### Adding Custom Features
[Dev Container Features](https://containers.dev/features) are self-contained, shareable units of installation code and configuration that let you quickly add tooling, runtimes, or libraries to your development container.
You can add features to your Dev Container by adding them to the `features` section of your `devcontainer.json` file:
```json theme={null}
{
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": { "moby": false },
"ghcr.io/devcontainers/features/github-cli:1": {}
}
}
```
Ona works well with many Dev Container Features, especially [official ones](https://containers.dev/features) designed for cloud-based environments. Linux-based runners generally provide best compatibility with most Dev Container Features. Here's what you should know:
* Community-supported features might require additional testing, as they may have been developed without specific consideration for compatibility.
* Feature behavior can vary depending on base images, other installed features, and specific configurations in your setup.
## Recovery mode
Recovery mode keeps the environment accessible when the configured Dev Container fails to build or start. Ona starts a temporary recovery container, mounts your workspace, and exposes it through the normal connection path so you can inspect logs, edit the Dev Container configuration, and rebuild.
Recovery mode does not apply your failed Dev Container image, features, lifecycle commands, or editor customizations. Use it only to repair the configuration. After a successful rebuild, Ona removes the temporary recovery container and reconnects to the rebuilt Dev Container.
When you enter recovery mode:
1. View the build logs:
```bash theme={null}
ona environment devcontainer logs
```
2. Fix the relevant Dev Container files, such as `.devcontainer/devcontainer.json`, `.devcontainer/Dockerfile`, or `.devcontainer/docker-compose.yml`.
3. Rebuild the Dev Container:
```bash theme={null}
ona environment devcontainer rebuild
```
## Next steps
* Explore the full [Dev Container specification](https://containers.dev/implementors/spec/) for advanced configurations
* Check out the [Dev Container Feature catalog](https://containers.dev/features) for additional tools and utilities
* Learn about [Ona projects](/docs/ona/projects/overview) to manage multiple environments
## Troubleshooting
1. Use the "Ask Ona" button in the startup accordion to get help diagnosing the failure. Ona analyzes the error logs and suggests fixes for common issues such as privileged operations, sudo commands, or image pull failures. This feature is available when Ona AI is enabled and your runner supports LLM capabilities.
2. Check the Ona console for specific error messages.
3. Ensure image versions are correctly specified.
4. If the environment enters [recovery mode](#recovery-mode), fix the configuration and rebuild the Dev Container.
If a lifecycle command like `postCreateCommand` appears to run inconsistently, view lifecycle command output in the environment logs under "Running dev container background commands".
Alternatively, you can also add logging to your script:
```bash theme={null}
exec >> /workspaces/post-create.log
exec 2>&1
set -x
```
Check `/workspaces/post-create.log` to see exactly what ran.
As an alternative to `postCreateCommand`, consider using [Tasks and Services](/docs/ona/configuration/tasks-and-services/overview) which provide UI visibility, CLI access, and structured triggers.
# Dotfiles
Source: https://ona.com/docs/ona/configuration/dotfiles/overview
Apply your shell, editor, and tool configurations to every Ona environment automatically.
Dotfiles apply your personal configurations (shell settings, aliases, editor preferences, tools) to every Ona environment on startup. Your customizations layer on top of the team's standardized Dev Container, so you get a consistent base with your own workflow.
## Configure your dotfiles repository
Point Ona at a Git repository containing your dotfiles. Every new environment will clone it and run your install script automatically.
**Via CLI:**
```bash theme={null}
ona user dotfiles set --repository https://github.com//dotfiles
```
**Via Web UI:**
Navigate to [Settings > Preferences](https://app.ona.com/settings/preferences) and enter the repository URL.
If you do not have a dotfiles repository yet, see [GitHub's dotfiles guide](https://dotfiles.github.io) or [awesome-dotfiles](https://github.com/webpro/awesome-dotfiles) for examples.
## How dotfiles are installed
When an environment starts, Ona:
1. Clones your dotfiles repository to `~/dotfiles`
2. Runs the **first** matching script it finds:
* `install.sh` or `install`
* `bootstrap.sh` or `bootstrap`
* `setup.sh` or `setup`
If none of these files exist, the repository is cloned but no script runs.
You are limited to one dotfiles repository per user.
## Update dotfiles in a running environment
Changes pushed to your dotfiles repository apply to **new** environments only. To update a running environment:
```bash theme={null}
cd ~/dotfiles && git pull && ./install.sh
```
Replace `install.sh` with whichever script your repository uses.
## Iterate on your dotfiles
To test changes without creating new environments each time:
1. Start an environment from your dotfiles repository
2. Edit files and re-run your install script to validate
3. Run `ona environment devcontainer rebuild` to reset the environment state if needed
## Change the default shell
Add this to your install script to switch to `zsh` (or any other shell):
```bash theme={null}
sudo chsh "$(id -un)" --shell "/usr/bin/zsh"
```
This modifies `/etc/passwd`, which persists across terminal sessions within the same environment.
## Best practices
* **Keep install scripts fast.** Every second adds to environment startup time.
* **Run non-interactively.** The install script runs without a TTY. Commands that prompt for input (e.g., `read`, interactive installers) will hang the environment.
* **Make scripts self-contained.** Check for dependencies before installing them, since Dev Container images vary across projects:
```bash theme={null}
FZF_VERSION="0.60.3"
if ! command -v fzf >/dev/null 2>&1; then
curl -L "https://github.com/junegunn/fzf/releases/download/v${FZF_VERSION}/fzf-${FZF_VERSION}-linux_amd64.tar.gz" | tar xzf -
sudo mv fzf /usr/local/bin
fi
echo "source <(fzf --zsh)" >> "$HOME/.zshrc"
```
* **Do not store secrets in dotfiles.** Use [Ona secrets](/docs/ona/configuration/secrets/overview) instead.
## Troubleshooting
Check the environment logs under "Creating Dev Container" for errors. A common cause:
```
fatal: repository 'https://github.com/user/dotfiles-does-not-exist/' not found
```
Verify the repository URL in [Settings > Preferences](https://app.ona.com/settings/preferences) points to an existing, accessible repository.
Clone errors appear in the environment logs, but install script failures may not. Reproduce the error manually:
```bash theme={null}
cd ~/dotfiles
./install.sh
```
If the script works in some projects but not others, the failing project's Dev Container image is likely missing a dependency your script needs. Make your script self-contained by checking for and installing missing dependencies (see the fzf example above).
The install script runs in a non-interactive shell without a TTY. Commands that expect terminal input will block indefinitely.
To diagnose:
1. Remove your dotfiles repository from [Settings > Preferences](https://app.ona.com/settings/preferences)
2. Start a fresh environment
3. Clone your dotfiles and run the install script manually to find the blocking command
4. Fix the script, push, and re-add the repository URL
# Multi-repository environments
Source: https://ona.com/docs/ona/configuration/multi-repository
Work with multiple repositories in a single environment for microservices and monorepo workflows.
Some projects span multiple repositories - microservices architectures, shared libraries, or related services that need to run together. Ona lets you clone additional repositories into your environment automatically.
This is valuable for agents too. When an agent needs to make coordinated changes across repositories, having them in one environment enables atomic commits and easier testing.
## Using Dev Container Configuration
The Dev Container `onCreateCommand` allows you to clone additional repositories when your environment starts. This method is particularly useful when you want to maintain the repository setup as part of your Dev Container configuration.
Add an `onCreateCommand` entry to your `.devcontainer/devcontainer.json` file:
```json theme={null}
{
"name": "One extra repository",
"image": "mcr.microsoft.com/devcontainers/universal:4.0.1-noble",
"onCreateCommand": "git clone https://github.com/organization/second-repo.git /workspaces/second-repo"
}
```
For multiple repositories:
```json theme={null}
{
"name": "Multiple repositories",
"image": "mcr.microsoft.com/devcontainers/universal:4.0.1-noble",
"onCreateCommand": "git clone https://github.com/organization/second-repo.git /workspaces/second-repo && git clone https://github.com/organization/third-repo.git /workspaces/third-repo"
}
```
## Using Ona Tasks and Services
Alternatively, you can use Ona's [Tasks and Services](/docs/ona/configuration/tasks-and-services/overview) to clone additional repositories. This approach offers more flexibility and can be combined with other environment tasks.
Add a task to your `.ona/config.yaml` file:
```yaml theme={null}
tasks:
build:
name: Clone additional repositories
command: |
git clone https://github.com/organization/second-repo.git /workspaces/second-repo
git clone https://github.com/organization/third-repo.git /workspaces/third-repo
triggeredBy: ['postDevcontainerStart']
```
## Best Practices
When working with multiple repositories, consider the following best practices:
* Clone repositories to `/workspaces`: Always clone additional repositories to `/workspaces/repo-name` (where `repo-name` in that example is the name of your repo). Do this to avoid git tracking issues within your main repository
* Use SSH keys or personal access tokens for authentication with private repositories
* Organize repositories in a consistent directory structure under `/workspaces`
* Configure Git identity globally to ensure consistent commits across repositories
## Working with Multiple Repositories
Once your environment is set up:
1. Navigate between repositories using the file explorer or terminal
2. Make changes in each repository independently
3. Commit and push changes to each repository separately
Example workflow:
```bash theme={null}
cd /workspaces/second-repo
# Make changes
git add .
git commit -m "Update feature X"
git push
cd /workspaces/third-repo
# Make changes
git add .
git commit -m "Fix bug Y"
git push
```
## Troubleshooting
Ensure you have the correct permissions and authentication method.
Use absolute paths when necessary.
Verify repository URLs and access permissions.
# Container registry
Source: https://ona.com/docs/ona/configuration/secrets/container-registry-secret
Authenticate with private container registries for Dev Container images.
Container registry secrets let you pull private Docker images for your Dev Containers. Credentials are also available inside your environment if your Dev Container includes the `docker` CLI.
This is how agents access custom tooling images your organization maintains in private registries.
## Create a container registry secret
1. Navigate to **Project → Secrets** or **Settings → Secrets**
2. Click **New Secret**, then choose **Container registry** from the **Secret type** dropdown
3. Configure:
* **Name**: Identifier for the secret
* **Registry hostname**: Your registry URL (see examples below)
* **Registry username**: Registry username
* **Registry password**: Registry password or access token
### Common registry hostnames
| Registry | Hostname |
| ------------------------- | --------------------------------------------- |
| Docker Hub | `https://index.docker.io/v1/` |
| GitHub Container Registry | `ghcr.io` |
| GitLab Container Registry | `registry.gitlab.com` |
| Azure Container Registry | `[name].azurecr.io` |
| Google Artifact Registry | `[region]-docker.pkg.dev` |
| AWS ECR | `[account-id].dkr.ecr.[region].amazonaws.com` |
## Cloud provider native authentication
For AWS and GCP, you can use runner-native authentication instead of managing credentials manually:
* **AWS ECR** (EC2 runners): See [AWS ECR with IAM authentication](#using-aws-ecr-with-iam-authentication) below
* **Google Artifact Registry** (GCP runners): See [Using Private GAR Images](/docs/ona/runners/gcp/private-gar-images)
## How it works
Container registry secrets serve two purposes:
1. **Pull Dev Container images**: Authenticate during environment creation to pull your private base image
2. **Access inside environments**: If your Dev Container includes `docker` CLI, Ona automatically runs `docker login`
For AWS ECR and Google Artifact Registry with runner-native auth, you won't be automatically logged in from within the environment. Use [AWS native auth](https://docs.aws.amazon.com/AmazonECR/latest/userguide/registry_auth.html), [gcloud auth](https://cloud.google.com/artifact-registry/docs/docker/authentication), or [Ona OIDC](/docs/ona/configuration/oidc) for additional access.
## Update a secret
1. Navigate to **Project → Secrets** or **Settings → Secrets**
2. Click **Edit**, update username/password, click **Update**
Updated credentials are automatically propagated to running environments (within 2 minutes).
***
## Using AWS ECR with IAM authentication
For AWS EC2 runners, you can use IAM-based authentication instead of managing ECR credentials manually.
### Prerequisites
* AWS EC2 runners for your Ona environments
* ECR registry in the same AWS account (or cross-account access configured)
### Setup
1. Navigate to **Project → Secrets → New Secret**
2. Choose **Container registry** from the **Secret type** dropdown
3. Enter your ECR hostname: `[account-id].dkr.ecr.[region].amazonaws.com`
4. Username and password auto-fill with `runner-native`
5. Click **Add**
### Configure IAM permissions
Add this policy to your environment instance role (find `EnvironmentRoleArn` in your CloudFormation stack outputs):
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ecr:GetAuthorizationToken"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability"
],
"Resource": "arn:aws:ecr:[region]:[account-id]:repository/[repository-name]"
}
]
}
```
Configure your ECR repository policy to allow the environment role:
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOnaEnvironmentPull",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::[account-id]:role/[environment-role-name]"
},
"Action": [
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchCheckLayerAvailability"
]
}
]
}
```
### Limitations
* ECR runner-native support is only available for AWS EC2 runners
* Existing environments must be recreated to apply permission changes
***
## Troubleshooting
After creating or updating a container registry secret, you must create a new environment for the changes to take effect. Restarting an existing environment may not apply the new authentication settings.
# Environment variables
Source: https://ona.com/docs/ona/configuration/secrets/environment-variables
Environment variable secrets are injected as standard environment variables when your environment starts. The secret name becomes the variable name.
```bash theme={null}
echo $APP_ENV
```
## When to use environment variables
Use environment variables for **non-sensitive configuration**:
* **Application modes** - `APP_ENV=development`, `DEBUG=true`
* **Feature flags** - `ENABLE_NEW_UI=true`
* **Endpoints** - `API_BASE_URL=https://api.example.com`
**Security tradeoff**: Environment variables can leak through process listings (`ps auxe`), logs, and crash dumps. [File secrets](/docs/ona/configuration/secrets/files) are more secure - they're not visible in process listings and won't appear in logs.
However, many tools (including MCP servers) expect credentials as environment variables. For API keys that can be rotated, this tradeoff is often acceptable. For passwords and private keys, prefer file secrets.
## Create an environment variable secret
1. Navigate to **Project → Secrets** or **Settings → Secrets**
2. Click **New Secret**, then choose **Environment variable** from the **Secret type** dropdown
3. Configure:
* **Name**: Variable name (e.g., `LINEAR_API_KEY`)
* **Secret**: The secret value (max 10KB)
## Access the variable
Available immediately in your environment:
```bash theme={null}
# In shell
echo $APP_ENV
# In Node.js
process.env.APP_ENV
# In Python
os.environ['APP_ENV']
```
## Update a secret
1. Navigate to **Project → Secrets** or **Settings → Secrets**
2. Click **Edit**, update the value, click **Update**
Updated values are automatically propagated to running environments (within 2 minutes). Running processes won't see the new value until the environment is restarted or the Dev Container is rebuilt.
# File secrets
Source: https://ona.com/docs/ona/configuration/secrets/files
File secrets mount sensitive data as files in your environment. They're created automatically when your environment starts, so applications (and agents) can read them like any other file.
## When to use file secrets
Use file secrets for:
* **Certificates and keys** - TLS certificates, SSH keys, service account credentials
* **Config files** - JSON configurations, kubeconfig, cloud provider configs
* **Multi-line content** - Anything that doesn't fit in an environment variable
Agents often need file secrets for SSH keys (Git operations), service account JSON files (cloud access), or config files that MCP servers expect at specific paths.
## Create a file secret
1. Navigate to **Project → Secrets** or **Settings → Secrets**
2. Click **New Secret**, then choose **File** from the **Secret type** dropdown
3. Configure:
* **Name**: Identifier for the secret
* **Secret**: File contents (max 10KB)
* **File Location**: Where the file appears in your environment (e.g., `/home/gitpod/.ssh/id_rsa`)
The file location cannot be changed after creation.
## Access the file
The file is automatically available at your specified path:
```bash theme={null}
cat /home/gitpod/.config/gcloud/application_default_credentials.json
```
No special code needed. Read it like any file.
## Update a file secret
1. Navigate to **Project → Secrets** or **Settings → Secrets**
2. Click **Edit**, update the value, click **Update**
Updated content is automatically propagated to running environments (within 2 minutes). The file at the mount path is updated in place.
# How secrets work
Source: https://ona.com/docs/ona/configuration/secrets/overview
Securely store API keys, tokens, and credentials for your environments and agents.
Secrets securely store and inject sensitive data into your environments - API keys, access tokens, credentials, and certificates that shouldn't be in source code.
Both humans and agents need secrets. When an agent connects to Linear, authenticates with AWS, or uses MCP servers, it pulls credentials from secrets you've configured.
Secrets are configured at three levels: organization, project, or user. They are automatically made available to any environment launched from that project. [Service accounts](/docs/ona/organizations/service-accounts#secrets) can also have secrets attached for use in automations. This ensures consistent and secure access to sensitive data across your development workflow.
## Secret Precedence
When secrets with the same name exist at different levels, they follow a strict precedence order:
1. **User Secrets** - Highest precedence
2. **Project Secrets** - Middle precedence
3. **Organization Secrets** - Lowest precedence
This means:
* User secrets override both project and organization secrets with the same name and mount
* Project secrets override organization secrets with the same name
* Organization secrets have the lowest priority
Learn more about managing [organization secrets](/docs/ona/organizations/organization-secrets), [project secrets](/docs/ona/projects/project-secrets), or [user secrets](/docs/ona/configuration/secrets/user-secrets).
## Encryption of Secrets
All secrets you create are protected with industry-standard encryption. Secrets can only be retrieved by environments created from your projects (for Project secrets) or your user (for User secrets).
We use `AES256-GCM` to encrypt all secrets at rest in the database, with an additional layer of protection through AWS RDS encryption. This dual-layer approach ensures your sensitive data remains secure both at the application level and infrastructure level. In transit, all secrets are encrypted using TLS.
**Ona employees do not have access to the encryption keys and cannot decrypt your secrets.**
## Secrets and environment lifecycle
When you create or update a secret, the change is automatically propagated to all running environments within the secret's scope (organization, project, or user). Propagation can take up to 2 minutes.
* **File secrets** are updated in place at their mount path.
* **Environment variable secrets** are updated on disk, but running processes won't see the new value until the environment is restarted or the Dev Container is rebuilt.
* **Container registry secrets** are updated, and new values are used the next time an image is pulled.
## Using secrets during builds
Organization and project secrets are automatically available during Dev Container image builds via [BuildKit secret mounts](https://docs.docker.com/build/building/secrets/#secret-mounts). No changes to `devcontainer.json` are needed. Your Dockerfile controls which `RUN` steps can access them using `--mount=type=secret`.
For setup instructions and examples, see [Using secrets during builds](/docs/ona/configuration/devcontainer/overview#using-secrets-during-builds).
## Types of secrets
* **[Environment Variables](/docs/ona/configuration/secrets/environment-variables)** - Key-value pairs injected into your environment
* **[Files](/docs/ona/configuration/secrets/files)** - Entire files (certificates, config files) injected into your environment
* **[Container Registry Secrets](/docs/ona/configuration/secrets/container-registry-secret)** - Authentication for private container registries
# User secrets
Source: https://ona.com/docs/ona/configuration/secrets/user-secrets
Personal secrets available across all your projects and environments.
User secrets are personal to you - your API keys, tokens, and credentials available in every environment you create. They're ideal for personal access tokens that shouldn't be shared with the team.
**User secrets have the highest precedence.** They override project and organization secrets with the same name, letting you customize without affecting teammates.
## When to use user secrets
Use user secrets when the credential belongs to an individual rather than to the team.
Common examples:
* your personal GitHub or GitLab token
* your personal Linear or Notion token
* credentials for tools only you should use
* temporary tokens you are testing before standardizing them at project or organization scope
## Manage user secrets
Navigate to **Settings → My Account → Secrets**.
From here you can create, edit, and delete secrets. Each secret can be an [environment variable](/docs/ona/configuration/secrets/environment-variables), [file](/docs/ona/configuration/secrets/files), or [container registry credential](/docs/ona/configuration/secrets/container-registry-secret).
## Common user secrets
| Secret | Purpose |
| ---------------- | --------------------------- |
| `LINEAR_API_KEY` | Personal Linear access |
| `GITHUB_TOKEN` | Personal GitHub token |
| `NPM_TOKEN` | Private npm registry access |
## When to use user vs project secrets
* **User secrets**: Personal tokens, credentials you don't want to share
* **Project secrets**: Shared team credentials, service accounts, project-specific config
## How user secrets interact with other scopes
If the same secret name exists at multiple levels:
1. user secret wins
2. project secret is used next
3. organization secret is the fallback
This is useful when the team defines a default token or endpoint but an individual needs to override it for debugging or personal access.
## Related
* [How secrets work](/docs/ona/configuration/secrets/overview)
* [Project secrets](/docs/ona/projects/project-secrets)
* [Organization secrets](/docs/ona/organizations/organization-secrets)
# Task & service examples
Source: https://ona.com/docs/ona/configuration/tasks-and-services/examples
Common patterns for database setup, preview servers, cloud auth, and more.
Copy and adapt these examples for your projects. These patterns work for both humans and agents. When an agent sees these tasks, it can use them as part of its run loop.
## Database provisioning
Start PostgreSQL and seed it with development data:
```yaml theme={null}
services:
postgresql:
name: PostgreSQL
description: Development database
triggeredBy:
- postDevcontainerStart
commands:
start: docker run --rm --name postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres:15
ready: docker exec postgres pg_isready -U postgres
stop: docker stop postgres
tasks:
seed:
name: Seed database
triggeredBy:
- manual
command: ./scripts/seed-dev-db.sh
```
## Containerized services
Run services in Docker containers using `docker run` directly. This gives you full control over ports, volumes, environment variables, and container entrypoints.
Do **not** use `docker run -d` (detached mode) in a service `start` command. The `-d` flag makes `docker run` exit immediately, which causes the service to transition to Stopped. Run containers in the foreground so the process stays alive.
```yaml theme={null}
services:
redis:
name: Redis
description: In-memory cache
triggeredBy:
- postDevcontainerStart
commands:
start: |
if docker inspect redis >/dev/null 2>&1; then
docker start -a redis
else
docker run --name redis -p 6379:6379 \
-e REDIS_MAXMEMORY=256mb \
-e REDIS_MAXMEMORY_POLICY=allkeys-lru \
redis:7-alpine
fi
ready: docker exec redis redis-cli ping | grep -q PONG
stop: docker stop redis
elasticsearch:
name: Elasticsearch
description: Search engine
triggeredBy:
- manual
commands:
start: |
if docker inspect elasticsearch >/dev/null 2>&1; then
docker start -a elasticsearch
else
docker run --name elasticsearch -p 9200:9200 \
-e discovery.type=single-node \
-e xpack.security.enabled=false \
-e ES_JAVA_OPTS="-Xms512m -Xmx512m" \
elasticsearch:8.11.0
fi
ready: curl -sf http://localhost:9200/_cluster/health
stop: docker stop elasticsearch
```
The `if docker inspect` pattern handles environment restarts — it reuses the existing container instead of failing on a name conflict.
## Prebuild optimization
Speed up environment starts by running tasks during prebuild:
```yaml theme={null}
tasks:
install-deps:
name: Install dependencies
description: Install and cache all dependencies
triggeredBy:
- prebuild
command: |
npm ci
go mod download
pip install -r requirements.txt
build-assets:
name: Build static assets
description: Compile CSS and bundle JavaScript
triggeredBy:
- prebuild
dependsOn:
- install-deps
command: npm run build:assets
warm-cache:
name: Warm build cache
description: Pre-compile common modules
triggeredBy:
- prebuild
dependsOn:
- install-deps
command: go build -v ./...
```
Tasks with the `prebuild` trigger run during [prebuild execution](/docs/ona/projects/prebuilds). Organization and project secrets are available, but user secrets are not.
## Build and test pipeline
Chain tasks with dependencies:
```yaml theme={null}
tasks:
build:
name: Build
command: yarn && yarn build
test:
name: Run tests
dependsOn:
- build
command: yarn test
setup:
name: Full setup
dependsOn:
- build
- test
triggeredBy:
- postDevcontainerStart
command: echo "Ready to develop"
```
Agents can run `test` knowing it will build first.
## Cloud authentication
Authenticate with AWS using Ona's identity provider:
```yaml theme={null}
tasks:
aws-auth:
name: AWS Auth
triggeredBy:
- postEnvironmentStart
command: ona idp login aws --role arn:aws:iam::123456789:role/dev-role
```
## Preview server
Serve your application for testing:
```yaml theme={null}
services:
preview:
name: Preview server
triggeredBy:
- postDevcontainerStart
commands:
start: |
npm install
npm run build
npx serve -p 3000 ./build
ready: curl -sf http://localhost:3000 > /dev/null
```
Agents can share this preview URL when demonstrating changes.
## Jupyter notebook
Start Jupyter for data science work:
```yaml theme={null}
services:
jupyter:
name: Jupyter Notebook
triggeredBy:
- manual
commands:
start: |
pip install jupyter pandas numpy matplotlib
jupyter notebook --ip=0.0.0.0 --no-browser
ready: curl -sf http://localhost:8888 > /dev/null
```
## Storybook
Component development with hot reload:
```yaml theme={null}
services:
storybook:
name: Storybook
triggeredBy:
- manual
commands:
start: yarn storybook
ready: curl -sf http://localhost:6006 > /dev/null
```
## Parallel database testing
Test against multiple database versions:
```yaml theme={null}
services:
pg14:
name: Postgres 14
commands:
start: docker run --rm --name pg14 -p 5432:5432 postgres:14
ready: docker exec pg14 pg_isready
stop: docker stop pg14
pg15:
name: Postgres 15
commands:
start: docker run --rm --name pg15 -p 5433:5432 postgres:15
ready: docker exec pg15 pg_isready
stop: docker stop pg15
tasks:
test-compat:
name: Compatibility tests
triggeredBy:
- manual
command: |
DATABASE_URL=postgres://localhost:5432 npm test
DATABASE_URL=postgres://localhost:5433 npm test
```
## Troubleshooting environment
Manual task for debugging production issues:
```yaml theme={null}
tasks:
troubleshoot:
name: Setup troubleshooting
triggeredBy:
- manual
command: |
sudo apt-get update && sudo apt-get install -y htop iftop
./scripts/setup-vpn.sh
```
# Dynamic configuration
Source: https://ona.com/docs/ona/configuration/tasks-and-services/generating-tasks-and-services
Generate tasks and services programmatically based on what agents discover in your codebase.
Create and update tasks and services at runtime using the CLI. When Ona explores a new repository, it can:
* Discover `package.json` scripts and expose them as tasks
* Find services in a monorepo and create start commands for each
* Generate test tasks for different modules it finds
* Adapt the environment to match the project structure
## Creating tasks and services dynamically
Use the CLI to pipe configuration directly:
```bash theme={null}
echo '{"tasks": {"update_deps": {"name": "Update dependencies", "command": "npm update"}}}' | ona environment config apply -
```
The `-` signals reading from stdin. Task and service IDs can only contain alphanumeric characters, underscores, and hyphens (1-128 characters).
## Example uses
**Expose package.json scripts as tasks:**
```bash theme={null}
jq -r '.scripts | to_entries[] | {(.key | gsub("[^a-zA-Z0-9_-]"; "_")): {"name": .key, "command": .value}}' package.json |
jq -s 'add | {"tasks": .}' |
ona environment config apply -
```
**Create services for monorepo components:**
```bash theme={null}
find ./components -type d -maxdepth 1 -mindepth 1 |
jq -R '{(. | gsub("[^a-zA-Z0-9_-]"; "_")): {"name": "Start " + ., "commands": {"start": "cd " + . + " && go run ."}}}' |
jq -s 'add | {"services": .}' |
ona environment config apply -
```
**Load configuration from a remote source:**
```bash theme={null}
curl https://example.com/tasks-and-services.json | ona environment config apply -
```
Only download configuration from sources you trust. Verify integrity before applying.
## Control from outside environments
Manage tasks and services from outside an environment using the CLI on your local machine or in external pipelines.
### Example: create, run task, clean up
```bash theme={null}
# Create environment
ENV_ID=$(ona environment create https://github.com/your-repo/project --dont-wait --class-id )
# Run a task
TASK_ID=$(ona environment task start build-and-test --environment-id $ENV_ID)
# Stream logs
ona environment task logs $TASK_ID --environment-id $ENV_ID
# Check result and clean up
TASK_STATUS=$(ona environment task get $TASK_ID --environment-id $ENV_ID -o json | jq -r .status)
if [ "$TASK_STATUS" = "succeeded" ]; then
ona environment delete $ENV_ID
else
echo "Task failed. Environment left for inspection."
fi
```
# Startup tasks & services
Source: https://ona.com/docs/ona/configuration/tasks-and-services/overview
Automate environment setup and define repeatable actions for humans and agents.
Tasks and services automate the repetitive work of setting up and operating development environments: seeding databases, starting servers, running tests, authenticating with cloud providers. Define it once and it runs automatically or on-demand.
For agents, tasks and services are essential. When Ona can run `npm test` or `docker compose up` reliably, it can iterate autonomously without human intervention.
## Tasks vs Services
In the session sidebar, long-running processes live under **Ports & Services** and one-off actions live under **Tasks**.
**Services** are long-running processes that stay active throughout your session. They appear in the **Ports & Services** tab alongside the ports they expose.
* Databases (PostgreSQL, MySQL)
* Backend and frontend servers
* Caching systems (Redis)
A service's `start` command must **stay running** (block) for the service to remain active. If the command exits, the service transitions to Stopped (exit code 0) or Failed (non-zero). For example, `npm start` or `docker run postgres` block and keep the service alive, while `docker run -d postgres` returns immediately and the service stops.
**Tasks** are one-off actions that run and complete. They appear in the **Tasks** tab and can run automatically during startup or manually on demand.
* Installing dependencies
* Running tests
* Seeding databases
* Authenticating with cloud providers
## Quick example
```yaml theme={null}
# .ona/config.yaml
services:
database:
name: PostgreSQL
commands:
start: docker compose up postgres
ready: docker compose exec postgres pg_isready
triggeredBy:
- postDevcontainerStart
tasks:
seed:
name: Seed database
command: npm run db:seed
triggeredBy:
- postDevcontainerStart
test:
name: Run tests
command: npm test
triggeredBy:
- manual
```
This configuration:
1. Starts PostgreSQL when the environment starts
2. Waits until the database service is ready
3. Seeds the database with test data
4. Makes "Run tests" available as a manual action
## Apply configuration changes
An environment keeps using the tasks and services configuration that it applied when it was created. Editing, moving, or deleting the configuration file does not change the running environment, including after the environment restarts.
When Ona detects a valid change, the environment start details show that an update is available. Select **Apply** to update that environment. Applying a change uses the latest configuration resolved from the repository; it does not change the Project setting.
If the Project's **Tasks and services configuration path** changed after the environment was created, select **Apply Project configuration** to adopt the new Project setting for that environment. This does not update other existing environments.
If the source file is missing or invalid, Ona keeps the last applied tasks and services running. Restore or fix the file before applying it. A missing or invalid explicitly configured file still prevents a new environment from loading tasks and services.
## Triggers
Control when tasks and services run:
| Trigger | Services | Tasks | When it runs |
| ----------------------- | -------- | ----- | ------------------------------------------------------------------------------------------------------------------ |
| `manual` | ✓ | ✓ | On-demand via the CLI or UI |
| `postDevcontainerStart` | ✓ | ✓ | After the Dev Container starts in a user environment (first start or rebuild). Does **not** fire during prebuilds. |
| `postEnvironmentStart` | ✓ | ✓ | Every time the environment starts or resumes |
| `prebuild` | ✓ | ✓ | During prebuild execution only (no user secrets available). Does **not** fire in user environments. |
See the [.ona/config.yaml schema](/docs/ona/reference/ona-config-schema#triggers) for complete trigger documentation, including [how triggers interact with prebuilds](/docs/ona/reference/ona-config-schema#prebuilds-and-triggers).
## Run automations across repositories
Tasks and services run within individual environments. For cross-repository automation at scale (migrations, security scanning, bulk updates), see [Automations](/docs/ona/automations/overview).
## Next steps
* [.ona/config.yaml schema](/docs/ona/reference/ona-config-schema) - field reference for all fields, commands, triggers, and execution environments
* [Examples](/docs/ona/configuration/tasks-and-services/examples) - common patterns for databases, servers, and CI
* [Dynamic configuration](/docs/ona/configuration/tasks-and-services/generating-tasks-and-services) - create tasks and services programmatically
# Create your first Automation
Source: https://ona.com/docs/ona/create-first-automation
Go from zero to a scheduled Automation: set up a project, make your repository AI-ready, and run your first closed-loop workflow.
This guide walks you from "I have an Ona account" to "I have a scheduled Automation running." By the end, you will have a project, a reproducible environment, and an Automation that runs on a schedule and delivers merge-ready pull requests.
## Prerequisites
Before you start:
* An Ona account on a **Core** or **Enterprise** plan
* At least one [runner](/docs/ona/runners/overview) in your organization
* A repository with code you want to automate against
## Step 1: Create a project
A project connects your repository to a runner. It is the blueprint for every environment and every Automation run.
If you already have a project for your repository, skip to Step 2.
Follow the [Create your first project](/docs/ona/create-first-project) guide to set one up. You need a repository URL, a project name, and at least one environment class.
## Step 2: Make your repository AI-ready
For Automations to work reliably, the environment must be reproducible. Every Automation run starts a fresh environment from your configuration. If the environment does not have your tools, dependencies, and services, the Automation cannot reliably clone, build, test, and iterate.
Two files make your repository AI-ready:
### devcontainer.json
Defines the base image, language runtimes, tools, and VS Code extensions. Place it at `.devcontainer/devcontainer.json` in your repository.
Minimal example:
```json theme={null}
{
"image": "mcr.microsoft.com/devcontainers/base:2.0.4-noble",
"features": {
"ghcr.io/devcontainers/features/node:1": {}
}
}
```
See [Set up your first environment](/docs/ona/configuration/devcontainer/getting-started) for the full configuration reference.
### .ona/config.yaml
Defines startup tasks (install dependencies, seed databases) and long-running services (databases, servers). Place it at `.ona/config.yaml` in your repository.
Minimal example:
```yaml theme={null}
tasks:
install:
name: Install dependencies
command: npm ci
triggeredBy:
- postDevcontainerStart
```
See [Tasks and Services](/docs/ona/configuration/tasks-and-services/overview) for the full configuration reference.
### Shortcut: use an Automation to generate your environment config
Bootstrap both files by creating an Automation with a single Prompt step. Create a new Automation, add one Prompt step with the following text, select your project, and run it. The Automation analyzes your repository and generates `devcontainer.json` and `.ona/config.yaml`.
```text theme={null}
Create a high-quality, fully working "development environment as code" configuration for the current environment.
The setup must work for:
- Ona development environments, which use DevContainer configurations.
- All Git repositories mounted under the DevContainer workspace.
Terminology
- apps: Source code intended to be built and shipped.
- dev tool: Any tool used for compiling, building, publishing, testing, profiling, debugging, or accessing an app's infrastructure.
Required Process
1. Read the documentation (see Allowed Sources) to fully understand:
- Ona tasks and services, secrets, environment variables, CLI, and prebuilds.
- DevContainer fundamentals and how they integrate with Ona and VS Code.
2. Analyze the source code and identify:
- Documentation on dev setup or contribution guidelines.
- Configuration files for containers, IDEs, build tools, environment variables, etc.
3. Update all necessary files, including:
- devcontainer.json
- Ona tasks and services
- Any other files required to meet the Success Criteria.
4. Run the Acceptance Tests for all code you have created and iterate until the last run of every Acceptance Test has been successful.
5. Do not create any documentation files.
Success Criteria
- The DevContainer includes all tools needed to work with any file in any repo in this environment.
- Ona services exist for every service required or recommended to run any app in this environment.
- Ona services exist for every app, for the standard or documented configurations.
- Ona tasks exist for all standard or documented development workflows for this repo.
- If an app exposes a TCP port, the DevContainer must forward it.
- If an app exposes an HTTP/HTTPS port, the corresponding Ona service must expose it by running "ona env port open" before starting the app.
- The DevContainer must install all VS Code extensions necessary to work effectively with the files and services in this environment.
Acceptance Tests
- The command "ona auto update " succeeds
- The command "ona env devcontainer validate" succeeds
- The DevContainer rebuilds successfully.
- All installed tools launch successfully and are available in the correct version
- Ona tasks start and finish successfully.
- Ona services successfully reach the state "ready".
- Apps exposed via Ona port respond successfully when curl'ing the port.
Allowed Sources
- Ona documentation: automations, secrets, environment variables, CLI, prebuilds, DevContainers
https://ona.com/docs/llms.txt
- DevContainer documentation: https://containers.dev/
- DevContainers in VS Code: https://code.visualstudio.com/docs/devcontainers/containers
- DevContainer base images: https://hub.docker.com/r/microsoft/devcontainers
- VS Code extensions:
- https://marketplace.visualstudio.com/vscode
- https://open-vsx.org/
- Any publicly available DevContainer features
- Anything installable within a Dockerfile
```
### Verify your environment
Start an environment from your project. Run your test suite. If everything passes interactively, it will work for Automations.
## Step 3: (Optional) Configure integrations
Integrations give Automations context from external tools. For example, the Sentry integration lets Automations read error data, and the Linear integration lets them read and update issues.
Configure integrations in **Settings > Integrations**. See the setup guides for [Sentry](/docs/ona/integrations/configure-sentry), [Linear](/docs/ona/integrations/configure-linear), [Notion](/docs/ona/integrations/configure-notion), [Granola](/docs/ona/integrations/configure-granola), and [Atlassian](/docs/ona/integrations/configure-atlassian).
## Step 4: (Optional, Enterprise) Create a service account
If you plan to run Automations on a schedule or share them with your team, create a [service account](/docs/ona/organizations/service-accounts). Commits, PRs, and comments will appear under the service account identity instead of your personal account. Service account executors require an Enterprise plan.
## Step 5: Create your first Automation
1. Go to **Automations** in Ona.
2. Click **New** and choose **Start from scratch** or pick a template from the suggestions panel.
### Name and description
To set or change the name and description, open the **⋯** menu and select **Rename**. A dialog opens where you can edit both fields.
### Set the executor
The **Run Automation as** field is in the trigger configuration panel. Click the trigger node to open the side panel — the executor selector is at the bottom.
* **Your user**: Automations run under your identity. Commits and PRs appear as you.
* **Service account** (Enterprise only): Automations run under a shared [service account](/docs/ona/organizations/service-accounts) identity.
Service account executors are an [Enterprise](/docs/ona/automations/plans-and-limits) feature. On Core plans, Automations run as your user.
### Add steps
Steps run in sequence. Example for a dependency update Automation:
**Step 1: Prompt**
```
Update all dependencies to their latest compatible versions.
Run the test suite and fix any breaking changes.
```
**Step 2: Command**
```bash theme={null}
npm test
```
**Step 3: Pull Request**
Create a PR with the changes for review.
### Set guardrails
[Guardrails](/docs/ona/automations/guardrails) prevent runaway executions:
* **Max concurrent**: 5 (for testing)
* **Max total**: 20
Increase these once you are confident the Automation works.
### Choose a trigger
For your first run, select **Manual** to test immediately.
| Trigger | Best for |
| ---------------- | ----------------------------------------- |
| **Manual** | One-time migrations, testing Automations |
| **Pull Request** | Code review, security checks, test runs |
| **Scheduled** | Recurring maintenance, dependency updates |
Click **Save** to create the Automation.
## Step 6: Run manually and verify
1. Open the Automation.
2. Select target repositories.
3. Click **Run**.
Watch the Automation execute. It starts an environment, runs your steps, and creates pull requests. Review the output and the PRs it created.
Start manual. Run the Automation a few times, review the results, and adjust steps as needed. Build confidence before scheduling.
## Step 7: Schedule it
Once you trust the output, switch the trigger to **Scheduled**:
1. Open the Automation settings.
2. Change the trigger to **Scheduled**.
3. Select **Every weekday** and set the time, for example 9:00 AM UTC for weekday mornings. Choose **Every day** instead if the Automation should also run on weekends.
4. Save.
The Automation now runs on schedule. You review merge-ready PRs instead of doing the work yourself.
## What's next
* [Automations in practice](/docs/ona/automations/automations-in-practice) for real-world examples
* [Configure Automations](/docs/ona/automations/configure-automations) for the full settings reference
* [Pull request triggers](/docs/ona/automations/triggers/pullrequest) for Automations that run on PR events
* [Time-based triggers](/docs/ona/automations/triggers/timebased) for scheduling options
* [Guardrails](/docs/ona/automations/guardrails) for safety controls
* [Service accounts](/docs/ona/organizations/service-accounts) for team-wide Automations
# Create your first project
Source: https://ona.com/docs/ona/create-first-project
Connect a repository to Ona so you can launch environments, configure Dev Containers, and run Automations against it.
A project connects a repository to Ona. It defines which runner provisions your environments, which environment classes are available, and what configuration files to use. Every environment and every Automation starts from a project.
## Prerequisites
* An Ona account on any plan
* At least one runner in your organization. Ona Cloud includes a runner by default. If you're self-hosting, [deploy a runner](/docs/ona/runners/overview) on [AWS](/docs/ona/runners/aws/overview) or [GCP](/docs/ona/runners/gcp/overview) first.
* A repository URL (GitHub or GitLab)
## Create the project
1. From the Ona dashboard, click **Projects** in the sidebar.
2. Click **New Project**.
3. Search for or browse to your repository.
4. Enter a project name.
5. Select at least one environment class. You can add up to 30 classes per project.
6. Click **Create**.
## Configure your environment
Every project reads two configuration files from your repository root. If a `devcontainer.json` doesn't exist yet, Ona generates a default one. Adding your own makes the environment match your project's needs.
* **`devcontainer.json`**: defines the base image, language runtimes, tools, and VS Code extensions. This is the [Dev Container](https://containers.dev/) standard, so the same file works in VS Code, GitHub Codespaces, and Ona. See [configure your Dev Container](/docs/ona/configuration/devcontainer/getting-started) for a walkthrough.
* **`.ona/config.yaml`**: defines startup tasks (install dependencies, seed databases) and long-running services (dev servers, databases). These run automatically when an environment starts. See [tasks and services](/docs/ona/configuration/tasks-and-services/overview) for examples.
By default, Ona looks for `.ona/config.yaml`. To use a different path, set the **Tasks and services configuration path** in your project settings.
Every environment and every Automation launched from this project uses the same configuration.
## Verify it works
1. Open the project from your dashboard.
2. Click **Create Environment**.
3. Wait for the environment to build and start.
4. Confirm your tools, dependencies, and services are available.
If the environment builds and your test suite passes, the project is ready for Automations.
## What's next
* [Create your first Automation](/docs/ona/create-first-automation) to run workflows against this project
* [Set up your first environment](/docs/ona/configuration/devcontainer/getting-started) to configure `devcontainer.json`
* [Share the project](/docs/ona/projects/project-sharing) with your team
* [Projects reference](/docs/ona/projects/overview) for environment classes, recommended editors, and advanced configuration
# Cursor
Source: https://ona.com/docs/ona/editors/cursor
Connect to Ona environments using Cursor editor.
[Cursor](https://www.cursor.com/) connects to Ona environments using the same [Ona extension](https://marketplace.visualstudio.com/items?itemName=gitpod.gitpod-flex) as VS Code. All [VS Code features](/docs/ona/editors/vscode) (rebuild, port forwarding, automations) work in Cursor.
When reaching out to support, specify that you are using Cursor as your editor.
## Prerequisites
1. [Cursor](https://www.cursor.com/) installed on your machine.
2. The [Ona extension](https://marketplace.visualstudio.com/items?itemName=gitpod.gitpod-flex) installed in Cursor.
3. The [Remote - SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) extension installed in Cursor.
## Opening an environment
Select **Cursor** from the editor dropdown by clicking the dropdown arrow next to the Open button on the action bar.
Cursor opens via the `cursor://` URI handler. On first use, Cursor prompts you to install the Ona extension and authenticate. This is the same flow as [VS Code setup](/docs/ona/editors/vscode#first-time-setup).
## Cursor AI works over SSH
Cursor's AI features work in Ona environments as they do locally:
* **Tab**: inline code completions
* **Agent**: multi-file AI edits
* **Chat** (⌘L / Ctrl+L): context-aware code chat
* **⌘K / Ctrl+K**: inline code generation and editing
Cursor AI communicates with Cursor's cloud services directly over the SSH connection. No Ona-specific configuration is needed.
## Extension and settings
Extensions configured via `customizations.vscode.extensions` in your `devcontainer.json` apply to Cursor. See [VS Code and forks](/docs/ona/editors/overview#vs-code-and-forks) for details.
## Troubleshooting
The `cursor://` URI handler is not registered on your system, or Cursor is not installed.
* **Linux**: Verify a Cursor desktop entry exists in `~/.local/share/applications` or `/usr/share/applications`. If missing, reinstall Cursor.
* **All platforms**: Refresh the browser page, or test in a different browser to rule out browser-specific issues.
The [VS Code troubleshooting guide](/docs/ona/editors/vscode#troubleshooting) applies to Cursor, including log export (`Ona: Export all logs`) and authentication issues.
1. Check the `Ona` output view for errors.
2. Check your network settings. VPN or firewall can interfere.
3. When sharing reports with support:
* Set log level to Trace via `Developer: Set Log Level...`
* Use `Ona: Export all logs` from the problematic window.
# JetBrains
Source: https://ona.com/docs/ona/editors/jetbrains
Integrate JetBrains IDEs with Ona
Ona integrates with JetBrains IDEs through [JetBrains Toolbox](https://www.jetbrains.com/toolbox-app/) and the [Ona plugin](https://plugins.jetbrains.com/plugin/26960-ona). Supported IDEs: IntelliJ IDEA Ultimate, GoLand, PyCharm Professional, PhpStorm, RubyMine, WebStorm, Rider, CLion, and RustRover.
## Prerequisites
1. [JetBrains Toolbox](https://www.jetbrains.com/toolbox-app/) installed on your system.
Keep JetBrains Toolbox updated for the best experience.
## Opening an environment
1. Start an environment in Ona.
2. Click the **dropdown arrow** next to the Open button on the action bar and select your preferred JetBrains IDE (e.g., IntelliJ IDEA Ultimate).
## First-time setup
On first use, JetBrains Toolbox will:
1. **Install the Ona plugin**. Click **Install** when prompted.
2. **Authenticate**. A browser window opens to sign in to your Ona account.
3. **Download the IDE backend**. Toolbox provisions the IDE backend in your environment.
4. **Launch the IDE client**. The local thin client opens and connects automatically.
If the Ona plugin does not appear as available in JetBrains Toolbox, your organization's enterprise settings may be blocking access to the JetBrains Marketplace. Check the Toolbox logs (Settings → About → "Show log files") for details, and work with your IT administrators to allow marketplace access.
## Faster startup with prebuilds
Enable [JetBrains warmup](/docs/ona/projects/prebuilds#jetbrains-warmup) in your project's prebuild configuration to reduce startup time. Warmup pre-installs the IDE backend and builds project indexes during prebuilds, so users skip those steps when opening the editor.
## Plugin customization
Add plugins to your `devcontainer.json` using the `customizations.jetbrains.plugins` property:
```json theme={null}
{
"customizations": {
"jetbrains": {
"plugins": [
"org.intellij.plugins.hcl",
"com.intellij.kubernetes"
]
}
}
}
```
### Finding plugin IDs
1. Visit the [JetBrains Marketplace](https://plugins.jetbrains.com/)
2. Search for your desired plugin
3. Copy the plugin ID from **Additional Information** at the bottom of the plugin details page
## Limitations
* JetBrains IDE settings (keymaps, themes, inspections) cannot be pre-configured via `devcontainer.json`. Configure them manually after connecting.
* Port forwarding configurations from `devcontainer.json` are not automatically applied. Expose ports manually through the IDE or CLI.
## Managing authentication
To change your Ona account or sign out:
1. Open JetBrains Toolbox
2. Go to Settings → Providers → Ona
3. Click "Sign Out"
4. Click "Sign In" to authenticate with a different account
## Rebuilding Dev Containers
1. Close your current IDE window
2. Wait for the rebuild to complete
3. Return to Ona and select the IDE in the action bar to reconnect
## Additional resources
* [JetBrains system requirements](https://www.jetbrains.com/help/ide-services/system-requirements.html)
* [JetBrains network requirements](https://www.jetbrains.com/help/ide-services/system-requirements.html#network-access-requirements)
* [IP allowlist for IntelliJ IDE](https://youtrack.jetbrains.com/articles/SUPPORT-A-288/Whats-the-IP-allowlist-of-IntelliJ-IDE-in-case-of-firewall-policy-or-restricted-network)
## Troubleshooting
1. Verify JetBrains Toolbox is running.
2. Ensure your environment is running in Ona.
3. Try closing the IDE and reopening from Ona.
**Toolbox logs**: Open JetBrains Toolbox → Settings → About → "Show log files" → send `toolbox.log` to [support@ona.com](mailto:support@ona.com).
**IDE logs**: Open JetBrains Toolbox → click the three dots next to the IDE entry → "Show log files" → send to [support@ona.com](mailto:support@ona.com).
Do **NOT** share logs publicly as they may contain sensitive information.
# Supported editors
Source: https://ona.com/docs/ona/editors/overview
IDEs & Editors supported by Ona
Ona environments connect to your editor over SSH. Most editors support **one-click open** from the dashboard. Click the Open button and you're connected. Editors like Zed require manual SSH configuration.
## Supported editors
| Editor | Connection | One-click open | Browser mode | Ona extension | devcontainer customizations | Prebuild warmup | Policy support |
| ---------------------------------------------- | ----------------- | --------------------- | --------------------- | ------------------------------- | -------------------------------------- | --------------------- | --------------------- |
| [VS Code](/docs/ona/editors/vscode) | SSH via extension | | - | | `vscode.extensions`, `vscode.settings` | - | |
| [VS Code Browser](/docs/ona/editors/vscode-browser) | Browser | | | | `vscode.extensions`, `vscode.settings` | - | |
| [Cursor](/docs/ona/editors/cursor) | SSH via extension | | - | | `vscode.extensions`, `vscode.settings` | - | |
| [Windsurf](/docs/ona/editors/windsurf) | SSH via extension | | - | | `vscode.extensions`, `vscode.settings` | - | |
| [JetBrains](/docs/ona/editors/jetbrains) | Toolbox plugin | | - | (Toolbox) | `jetbrains.plugins` | | |
| [Zed](/docs/ona/editors/zed) | SSH (manual) | - | - | - | - | - | - |
## VS Code and forks
[VS Code](/docs/ona/editors/vscode), [Cursor](/docs/ona/editors/cursor), and [Windsurf](/docs/ona/editors/windsurf) all use the same [Ona extension](https://marketplace.visualstudio.com/items?itemName=gitpod.gitpod-flex). The extension connects to your environment over SSH and provides:
* **One-click rebuild**: apply devcontainer changes without leaving the editor
* **Port forwarding**: access services running in your environment
* **Automations management**: start/stop services and tasks
* **Browser handling**: URLs opened in the environment automatically open in your local browser
Cursor and Windsurf are AI-native editors built on VS Code. Their AI features work in Ona environments as they do locally, operating over the SSH connection independently of the Ona extension. See the [Cursor](/docs/ona/editors/cursor#cursor-ai-works-over-ssh) and [Windsurf](/docs/ona/editors/windsurf#windsurf-ai-works-over-ssh) pages for specifics.
Extensions configured via `customizations.vscode.extensions` in your `devcontainer.json` are installed in all VS Code-based editors, including Cursor and Windsurf.
## JetBrains
[JetBrains IDEs](/docs/ona/editors/jetbrains) connect through JetBrains Toolbox with the [Ona plugin](https://plugins.jetbrains.com/plugin/26960-ona). Supported IDEs: IntelliJ IDEA Ultimate, GoLand, PyCharm Professional, PhpStorm, WebStorm, RubyMine, CLion, RustRover, and Rider.
JetBrains is the only editor family that supports [prebuild warmup](/docs/ona/projects/prebuilds#jetbrains-warmup). Warmup pre-installs the IDE backend and builds project indexes during prebuilds, reducing startup time.
Plugins are configured via `customizations.jetbrains.plugins` in your `devcontainer.json`.
## SSH-based editors
[Zed](/docs/ona/editors/zed) and any other SSH-capable editor can connect to Ona environments using the [CLI](/docs/ona/integrations/cli). Run `ona env ssh-config` to set up your local SSH configuration, then connect using the environment's SSH host (`.ona.environment`).
SSH-based editors do not appear in the Ona dashboard editor selector and are not covered by [organization editor policies](/docs/ona/organizations/overview).
## Browser handling
VS Code, VS Code forks (Cursor, Windsurf), and JetBrains have built-in browser handlers that automatically open URLs in your local browser when triggered by scripts or commands. See [opening a port and previewing in the browser](/docs/ona/integrations/ports#opening-a-port-and-previewing-in-the-browser) for details.
# Visual Studio Code
Source: https://ona.com/docs/ona/editors/vscode
Connect to Ona environments using Visual Studio Code with the Ona extension.
Ona integrates with VS Code over SSH. The [Ona extension](https://marketplace.visualstudio.com/items?itemName=gitpod.gitpod-flex) handles connection setup, environment management, and port forwarding.
## Prerequisites
1. [VS Code](https://code.visualstudio.com/download) installed.
2. The [Ona](https://marketplace.visualstudio.com/items?itemName=gitpod.gitpod-flex) extension installed.
3. The [Remote - SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) extension installed.
Keep your VS Code and extensions updated for the best experience.
## Opening an environment
1. Start an environment in Ona.
2. Click the **Open** button on the action bar. This opens the environment in your default editor. The button is available at any stage, even when the environment is not fully running yet.
3. To choose a different editor, click the **dropdown arrow** next to the Open button and select from the list.
## First-time setup
On first use, VS Code will prompt you to:
1. **Install the Ona extension**. Click **Allow** when prompted. The extension configures your local SSH settings automatically.
2. **Install Remote - SSH**. Click **Install** if prompted. This extension is required for the SSH connection.
3. **Authenticate**. A browser window opens to sign in to your Ona account. After signing in, you are redirected back to VS Code.
If authentication fails, close the browser tab and try opening the environment again.
## Workspace Trust
VS Code may prompt you to trust the workspace when connecting to a new environment. Ona environments run in isolated VMs, so you can safely click **Trust Folder & Continue** if you're familiar with the repository. See the [VS Code documentation](https://code.visualstudio.com/editor/workspace-trust) for details.
## Managing your environment
### Commands
Open the Command Palette (`Cmd+Shift+P` / `Ctrl+Shift+P`) and type `Ona` to see all available commands. You can also click the **remote indicator** in the bottom-left corner for a quick menu.
### Rebuild
Rebuild the container to apply changes to `.devcontainer.json`, `Dockerfile`, or `docker-compose.yml`:
1. **Command Palette**: `Ona: Rebuild Container`
2. **Prompt**: VS Code detects configuration changes and offers to rebuild automatically.
You will be disconnected during the rebuild and reconnected when it finishes. Check the `Ona` output channel for rebuild logs.
## Uninstalling
Run `Ona: Uninstall Extension` to remove the extension and clean up SSH configuration. Removing the extension through VS Code's extension panel does not clean up SSH settings.
If you already removed the extension without using the command, reinstall it and run the uninstall command.
## Troubleshooting
* Port forwarding does not work for hosts other than `localhost` (e.g., other services in a docker-compose.yml).
* **Workaround**: Use `network_mode: host` in your docker-compose.yml for services you want to port forward.
* `remoteEnv` environment variable values are not applied unless the Dev Container is rebuilt.
If a build fails, you enter [recovery mode](/docs/ona/configuration/devcontainer/overview#recovery-mode):
1. Check the error messages in the `Ona` output channel.
2. Inspect the build logs in the Output panel.
3. Fix the `.devcontainer.json` configuration.
4. Rebuild using `Ona: Rebuild Container`.
[Recovery mode](/docs/ona/configuration/devcontainer/overview#recovery-mode) is not stable for development. Fix the configuration and rebuild.
1. Use `Ona: Sign Out` to sign out.
2. Sign in again with the same or a different account.
Allow VS Code's "Code Helper.app" in your firewall settings, then restart VS Code and rebuild.
1. Check the `Ona` output view for errors.
2. Check your network settings. VPN or firewall can interfere.
3. When sharing reports with support:
* Set log level to Trace via `Developer: Set Log Level...`
* Set `remote.SSH.logLevel` to `trace` in VS Code settings.
* Use `Ona: Export all logs` from the problematic window.
Be cautious when sharing logs, as they may contain sensitive information.
# VS Code browser
Source: https://ona.com/docs/ona/editors/vscode-browser
Connect to Ona environments using VS Code in the browser with zero installation.
VS Code Browser runs in the browser with no local installation. No extensions or SSH configuration required.
## Opening an environment
1. Start an environment in Ona.
2. Click the **Code** tab in the environment details page. VS Code Browser loads inline alongside the Ona session.
3. To open VS Code Browser in a dedicated browser tab, select **VS Code Browser** from the editor dropdown next to the Open button on the action bar.
4. On first use, click **Allow** when prompted to authenticate with your Ona account.
If authentication fails, close the browser tab and try opening the environment again.
## Managing your environment
### Commands
Open the Command Palette (`Cmd+Shift+P` / `Ctrl+Shift+P`) and type `Ona` to see all available commands.
### Rebuild
Rebuild the container to apply changes to `.devcontainer.json`, `Dockerfile`, or `docker-compose.yml`:
1. **Command Palette**: `Ona: Rebuild Container`
2. **Prompt**: VS Code detects configuration changes and offers to rebuild automatically.
You will be disconnected during the rebuild and reconnected when it finishes. Check the `Ona` output channel for rebuild logs.
### Full-screen editing
Use the **Expand** button in the top-right corner of the Code tab for a larger view, or select **VS Code Browser** from the editor dropdown to open in a dedicated browser tab.
### Settings Sync
Enable Settings Sync to sync your extensions and preferences from VS Code Desktop. See the [official Settings Sync documentation](https://code.visualstudio.com/docs/configure/settings-sync#_turning-on-settings-sync).
## Troubleshooting
The following limitations apply in addition to the [VS Code Desktop limitations](/docs/ona/editors/vscode#limitations):
* Docker Compose environments require `network_mode: "host"` on the main service for VS Code Browser to connect.
* VS Code Browser is not supported for local environments created using Ona Desktop.
* Opened ports are not automatically forwarded. [Share them](/docs/ona/integrations/ports#open-ports) to access them.
1. Use `Ona: Sign Out` to sign out.
2. Sign in again with the same or a different account.
1. Check the `Ona` output view for errors.
2. When sharing reports with support:
* Set log level to Trace via `Developer: Set Log Level...`
* Use `Ona: Export all logs` from the problematic window.
Be cautious when sharing logs, as they may contain sensitive information.
# Windsurf
Source: https://ona.com/docs/ona/editors/windsurf
Connect to Ona environments using Windsurf editor.
[Windsurf](https://windsurf.com/) connects to Ona environments using the same [Ona extension](https://marketplace.visualstudio.com/items?itemName=gitpod.gitpod-flex) as VS Code. All [VS Code features](/docs/ona/editors/vscode) (rebuild, port forwarding, automations) work in Windsurf.
When reaching out to support, specify that you are using Windsurf as your editor.
## Prerequisites
1. [Windsurf](https://windsurf.com/) installed on your machine.
2. The [Ona extension](https://marketplace.visualstudio.com/items?itemName=gitpod.gitpod-flex) installed in Windsurf.
3. The [Remote - SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) extension installed in Windsurf.
## Opening an environment
Select **Windsurf** from the editor dropdown by clicking the dropdown arrow next to the Open button on the action bar.
Windsurf opens via the `windsurf://` URI handler. On first use, Windsurf prompts you to install the Ona extension and authenticate. This is the same flow as [VS Code setup](/docs/ona/editors/vscode#first-time-setup).
## Windsurf AI works over SSH
Windsurf's AI features work in Ona environments as they do locally:
* **Cascade**: AI assistant for multi-step tasks
* **Flows**: context-aware actions triggered from the editor
* **Supercomplete**: code completions
* **Chat**: inline AI chat for code questions
Windsurf AI communicates with Windsurf's cloud services directly over the SSH connection. No Ona-specific configuration is needed.
## Extension and settings
Extensions configured via `customizations.vscode.extensions` in your `devcontainer.json` apply to Windsurf. See [VS Code and forks](/docs/ona/editors/overview#vs-code-and-forks) for details.
## Troubleshooting
The `windsurf://` URI handler is not registered on your system, or Windsurf is not installed.
* **Linux**: Verify a Windsurf desktop entry exists in `~/.local/share/applications` or `/usr/share/applications`. If missing, reinstall Windsurf.
* **All platforms**: Refresh the browser page, or test in a different browser to rule out browser-specific issues.
The [VS Code troubleshooting guide](/docs/ona/editors/vscode#troubleshooting) applies to Windsurf, including log export (`Ona: Export all logs`) and authentication issues.
1. Check the `Ona` output view for errors.
2. Check your network settings. VPN or firewall can interfere.
3. When sharing reports with support:
* Set log level to Trace via `Developer: Set Log Level...`
* Use `Ona: Export all logs` from the problematic window.
# Zed
Source: https://ona.com/docs/ona/editors/zed
Connect to Ona environments using Zed editor via SSH.
Zed connects to Ona environments over SSH. It does not use the one-click open flow in the dashboard, so setup requires the [Ona CLI](/docs/ona/integrations/cli).
## Prerequisites
1. [Zed](https://zed.dev/download) installed.
2. The [Ona CLI](/docs/ona/integrations/cli) installed.
## Connecting to an environment
1. Run `ona env ssh-config` to configure your local SSH settings. Verify `~/.ssh/ona` exists after running.
2. Start an environment in Ona. Copy the SSH host from the environment details page. The format is `.ona.environment` (e.g., `01922350-2462-79da-8c80-770fe4275aa2.ona.environment`).
3. In Zed, open the remote projects dialog (`Cmd+Shift+P`, type `remote`). Add a connection using the SSH host.
Once connected, you have access to the repository, tools, and services in the environment. Ensure the environment has started before connecting.
## Troubleshooting
Confirm the environment is running and copy the host again from the environment details page.
Rerun `ona env ssh-config` on your local machine and check that `~/.ssh/ona` exists.
The issue is usually in the environment configuration rather than in Zed itself.
See [Zed remote development docs](https://zed.dev/remote-development) and the [Ona CLI](/docs/ona/integrations/cli) page for more.
# Using environments from external agents
Source: https://ona.com/docs/ona/environments/agent-environments
Manage Ona environments from external AI agents like Claude Code or Cursor using the Ona CLI.
Use the Ona CLI to create, manage, and run commands in environments from external AI agents such as Claude Code, Cursor, or custom scripts. This guide covers the full lifecycle: discover resources, create an environment, execute commands, and clean up.
## Prerequisites
* [Ona CLI installed](/docs/ona/integrations/cli)
* Authenticated via `ona login`
* At least one [runner](/docs/ona/runners/ona-cloud) available in your organization
## Discover projects
List projects to find one to create an environment from:
```bash theme={null}
ona project list
```
Use `-o json` for machine-readable output:
```bash theme={null}
ona project list -o json
```
## Discover environment classes
Environment classes define the compute resources (CPU, memory) for your environment. List available classes:
```bash theme={null}
ona environment list-classes
```
Filter by runner:
```bash theme={null}
ona environment list-classes --runner
```
## Create an environment
### From a project
The simplest way. The project already has a repository URL, environment class, and configuration:
```bash theme={null}
ona environment create
```
### From a context URL
Create directly from a repository URL. Requires an environment class:
```bash theme={null}
ona environment create --class-id
```
Both creation methods support `--inactivity-timeout` to set a custom auto-stop timeout. See [auto-stop timeout](/docs/ona/organizations/policies/environment-timeout) for details and examples.
### Non-blocking creation
Use `--dont-wait` to return the environment ID immediately without waiting for it to start:
```bash theme={null}
ENV_ID=$(ona environment create --dont-wait)
```
Then poll for readiness:
```bash theme={null}
ona environment get "$ENV_ID" -o json
```
## List environments
```bash theme={null}
ona environment list
```
Filter to JSON for parsing:
```bash theme={null}
ona environment list -o json
```
## Run commands
Execute commands inside a running environment using `exec`:
```bash theme={null}
ona environment exec --
```
The command runs inside the environment's dev container via the EnvironmentOps API (not SSH). The CLI waits for the command to complete and prints stdout/stderr.
### Examples
```bash theme={null}
# Run a build
ona environment exec -- make build
# Run tests with a longer timeout
ona environment exec --timeout 300 -- npm test
# Run in a specific directory
ona environment exec --working-dir /workspace/myproject -- cargo test
# Get structured output for parsing
ona environment exec -o json -- echo hello
```
### Exit codes
The CLI exits with the same exit code as the remote command. A non-zero exit code means the command failed.
### Flags
| Flag | Default | Description |
| --------------- | ---------------- | ---------------------------------------- |
| `--timeout` | `120` | Command timeout in seconds |
| `--working-dir` | workspace folder | Working directory inside the environment |
| `-o json` | table | Output format (json, yaml, table) |
## SSH access
For interactive sessions or when you need a persistent shell:
```bash theme={null}
ona environment ssh
```
Run a single command over SSH:
```bash theme={null}
ona environment ssh -- ls -la
```
See the [CLI reference](/docs/ona/reference/cli) for SSH setup details.
## Clean up
Stop an environment to preserve its state:
```bash theme={null}
ona environment stop
```
Delete an environment permanently:
```bash theme={null}
ona environment delete
```
## Full workflow example
End-to-end script that creates an environment, runs a command, and cleans up:
```bash theme={null}
#!/bin/bash
set -euo pipefail
# Create environment from a project, wait for it to start
ENV_ID=$(ona environment create --dont-wait)
echo "Created environment: $ENV_ID"
# Wait for the environment to be running
ona environment start "$ENV_ID"
# Run commands
ona environment exec "$ENV_ID" -- npm install
ona environment exec "$ENV_ID" --timeout 300 -- npm test
# Clean up
ona environment delete "$ENV_ID"
echo "Done"
```
### JSON workflow for agents
Agents that parse structured output can use `-o json` throughout:
```bash theme={null}
# Create and capture the environment ID (--dont-wait prints the ID directly)
ENV_ID=$(ona environment create --dont-wait)
# Check status
STATUS=$(ona environment get "$ENV_ID" -o json | jq -r '.[0].phase')
# Run a command and parse the result
RESULT=$(ona environment exec "$ENV_ID" -o json -- echo hello)
EXIT_CODE=$(echo "$RESULT" | jq -r '.[0].exit_code')
STDOUT=$(echo "$RESULT" | jq -r '.[0].stdout')
```
# Archive & auto-delete
Source: https://ona.com/docs/ona/environments/archive-auto-delete
How Ona archives and deletes inactive environments.
Ona manages inactive environments in two stages: archival after a period of inactivity, then auto-deletion based on your plan and organization policy.
## Timelines
| Plan | Archive after | Auto-delete after archival |
| ---------- | ---------------------------------------------- | ---------------------------------- |
| Core | 3 days | 4 days |
| Enterprise | 3 days by default; configurable from 1-30 days | Configurable (1-4 weeks, or never) |
## Archiving
Stopped environments are archived after the inactive period for your plan. Enterprise organization policies can replace the default archive timing. You can also archive an environment manually from its actions menu or the CLI:
```bash theme={null}
ona environment archive
```
If the environment is running, Ona stops it before moving it to Archived. The CLI accepts an environment ID, unique partial ID, or exact name.
Archived environments move to a separate view and can be unarchived or deleted. You receive an email when environments are archived automatically.
## Viewing archived environments
Open **User settings > Archived sessions** to view archived environments.
## Managing archived environments
Select archived environments with the row checkboxes to use bulk actions, or open a row's actions menu to manage one environment.
* **Unarchive** - returns the environment to your main list.
* **Delete** - permanently removes the environment after you confirm.
Deleting an environment permanently removes all content. This cannot be undone.
## Archive timing settings
Enterprise admins can configure when stopped environments move to Archived from **Settings > Organization > Policies**. The minimum is 1 day and the maximum is 30 days. Core organizations archive stopped environments after 3 days. See [Archive timing policy](/docs/ona/organizations/policies/archive-timing) for details.
## Auto-delete settings
Options: **After 1 day**, **After 2 days**, **After 3 days**, **After 4 days**, **After 5 days**, **After 1 week**, **After 2 weeks**, **After 4 weeks**, or **Never**.
Auto-delete preferences are available on Enterprise plans. Core organizations auto-delete environments 4 days after archival.
Organization policies and plan limits override user preferences when more restrictive. Disabled options in the dropdown indicate those restrictions.
## FAQ
Core environments archive after 3 days of inactivity. Enterprise environments archive after 3 days by default, or after the organization policy period.
No. Only archived environments can be restored.
Your organization policy enforces a maximum retention period.
Automatic archival only applies to stopped environments. If you archive a running environment manually, Ona stops it before moving it to Archived.
Check organization policy restrictions.
# Development environments
Source: https://ona.com/docs/ona/environments/overview
Isolated development workspaces for humans and agents.
Ona environments are isolated development workspaces for humans and agents. Each environment combines compute, storage, your repository, and your development tooling into a reproducible setup.
## Key concepts
* **[Projects](/docs/ona/create-first-project)**: connect a repository to Ona with shared configuration, access controls, and secrets.
* **Environments**: running workspaces for development, review, debugging, or focused tasks.
* **[Codex Agent](/docs/ona/agents/codex)**: works inside environments with the same tools a developer would use.
* **[Automations](/docs/ona/automations/overview)**: create environments on triggers like PRs, schedules, or webhooks.
## What's inside an environment
| Component | Description |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Compute | From [Ona Cloud](/docs/ona/runners/ona-cloud) or your own [runner](/docs/ona/runners/overview) |
| Dev Container | Image, tools, extensions, and workspace setup. See [Container configuration](/docs/ona/configuration/devcontainer/overview) |
| Tasks & services | Databases, servers, watchers. See [Startup tasks & services](/docs/ona/configuration/tasks-and-services/overview) |
| Dotfiles | Personal shell and editor customization. See [Dotfiles](/docs/ona/configuration/dotfiles/overview) |
| Editor access | Browser, VS Code, Cursor, JetBrains, CLI, or SSH. See [Editors](/docs/ona/editors/overview) |
## Lifecycle
* **Create**: start an environment from a project — choose a branch and environment class.
* **Provision**: Ona sets up compute, starts your Dev Container, and runs setup hooks.
* **Work**: you or an agent connect and start developing.
* **Stop**: storage persists so you can resume later.
* **Archive**: after inactivity, Ona [archives and can auto-delete](/docs/ona/environments/archive-auto-delete) the environment.
## Storage and isolation
Environments are isolated from each other. Storage persists across stops and starts of the same environment. Creating a new environment starts fresh from the project configuration and any available prebuild.
See [Persistent storage](/docs/ona/environments/persistent-storage) for what survives Dev Container rebuilds and how prebuilds interact with storage. To share a running service, use [port sharing](/docs/ona/integrations/ports).
## Faster starts
[Prebuilds](/docs/ona/projects/prebuilds) snapshot your Dev Container setup so new environments skip slow installation steps. On supported AWS runners, [warm pools](/docs/ona/projects/warm-pools) keep pre-initialized instances ready.
## Configuration
* **[Container configuration](/docs/ona/configuration/devcontainer/overview)**: image, tools, mounts, editor customizations
* **[Startup tasks & services](/docs/ona/configuration/tasks-and-services/overview)**: long-running processes and one-off tasks
* **[Dotfiles](/docs/ona/configuration/dotfiles/overview)**: personal shell and editor setup
* **[Multi-repository environments](/docs/ona/configuration/multi-repository)**: work across multiple repos
New to Ona? Start with [Set up your first environment](/docs/ona/configuration/devcontainer/getting-started).
# Persistent storage
Source: https://ona.com/docs/ona/environments/persistent-storage
What persists in Ona environments across stops, starts, and Dev Container rebuilds.
Ona environments use persistent storage attached to the underlying VM. Everything on disk persists across environment stops and starts.
## What persists
* `/workspaces/` - your cloned repository and any changes
* `/home/gitpod` - home directory, shell history, installed tools
* System packages installed during setup
* Files created anywhere on the filesystem
Stop an environment, come back later, and continue where you left off.
## Dev Container rebuilds
Rebuilding your Dev Container recreates most of the filesystem from the image. Your repository at `/workspaces/` persists via a bind mount - code and uncommitted changes remain intact.
To persist other directories across rebuilds, add bind mounts in your `devcontainer.json`:
```json theme={null}
{
"mounts": [
"source=/workspaces/.cache,target=/home/gitpod/.cache,type=bind"
]
}
```
## Prebuilds and storage
[Prebuilds](/docs/ona/projects/prebuilds) snapshot the entire Dev Container filesystem - installed dependencies, built artifacts, and all files. New environments load from this snapshot instead of running setup from scratch.
## Storage size
Storage size is configured through [environment classes](/docs/ona/runners/aws/environment-classes). Each runner type ([Ona Cloud](/docs/ona/runners/ona-cloud), [AWS](/docs/ona/runners/aws/environment-classes), [GCP](/docs/ona/runners/gcp/overview)) provides classes with different disk sizes. Use storage larger than RAM.
## Storage lifecycle
| State | Storage |
| --------------------------------------------------------------------------------------- | ---------------------------- |
| Stopped | Persists - resume anytime |
| Archived (after inactivity, [by plan or policy](/docs/ona/environments/archive-auto-delete)) | Persists - can be unarchived |
| Deleted | Permanently removed |
## Ephemeral vs persistent
For agents, the recommended workflow is [ephemeral environments](/docs/ona/configuration/devcontainer/optimizing-startup-times) - one fresh environment per task for isolation. With prebuilds, starting fresh is fast enough that persistence is not needed.
For human developers, persistent environments work well for longer-running tasks where you want to maintain state across sessions.
## Troubleshooting
Check usage with `df -h`. Select the **Regular** environment class (80 GB), or choose a larger class if your plan supports it.
# Overview
Source: https://ona.com/docs/ona/getting-started
The platform for background agents.
Ona is the platform for background agents. Run a team of AI software engineers in the cloud, orchestrated, governed, and secured at the kernel.
Get started in less than 5 minutes on [Ona Cloud](/docs/ona/runners/ona-cloud), or run Ona in your own VPC on [AWS](/docs/ona/runners/aws/overview) or [GCP](/docs/ona/runners/gcp/overview). Start a single interactive session, or run fleets of agents in the background on a schedule, on pull request events, or from your issue tracker.
Here's what you can do with Ona:
* **Create reproducible environments**: Define your dev setup as code with [Dev Containers](/docs/ona/configuration/devcontainer/overview) and [Automations](/docs/ona/automations/overview), so every environment starts identically. No "works on my machine" problems
* **Write code**: Describe what you want to build, and Ona will implement it. Bring your configuration from Claude Code or Cursor, or add an [AGENTS.md](/docs/ona/agents-md) and [skills](/docs/ona/agents/skills) to make Ona even more productive
* **Automate software development**: Assign issues to Ona in [Linear](/docs/ona/integrations/configure-linear) or trigger agents on [pull request events](/docs/ona/automations/triggers/pullrequest). Anything your engineering team can do, Ona can do it too
* **Integrate with your stack**: Connect [source control](/docs/ona/source-control/overview), [IDEs](/docs/ona/editors/overview), and tools like [Jira](/docs/ona/integrations/configure-atlassian) and [Notion](/docs/ona/integrations/configure-notion)
* **Govern at scale**: Enforce policies, audit changes, and control agent execution with [guardrails](/docs/ona/guardrails/overview)
* **Secure by design**: Ephemeral, isolated environments with [SSO](/docs/ona/sso/overview), [OIDC](/docs/ona/configuration/oidc), and SCIM built in
Get started with Ona →
# Browser extension
Source: https://ona.com/docs/ona/integrations/browser-extension
One-click environment creation from GitHub, GitLab, Bitbucket, and Azure DevOps.
The browser extension adds an "Open in Ona" button to repository pages on GitHub, GitLab, Bitbucket, and Azure DevOps (including self-hosted instances).
## Install
| Browser | Link |
| ------------------- | ---------------------------------------------------------------------------------------------------- |
| Chrome, Edge, Brave | [Chrome Web Store](https://chromewebstore.google.com/detail/gitpod/dodmmooeoklaejobgleioelladacbeki) |
| Firefox | [Firefox Add-ons](https://addons.mozilla.org/en-US/firefox/addon/onahq/) |
## Settings
Click the extension icon in your browser toolbar to access settings. The settings panel is the same across Chrome, Edge, Brave, and Firefox.
## Self-hosted SCM providers
The extension works automatically on `github.com`, `gitlab.com`, `bitbucket.org`, and `dev.azure.com`. For self-hosted instances (GitLab CE/EE, Bitbucket Datacenter), enable **Run on all sites** in the extension settings, or right-click the extension icon and select **Enable on this domain**.
## Custom Ona instance
If using a self-hosted Ona instance, open the extension settings and enter your instance URL.
## Migrating from Gitpod Classic
If the extension's "Open" button launches Gitpod Classic instead of Ona, update the Ona URL:
1. Click the extension icon in your browser toolbar
2. Either enable **Automatic instance hopping** and visit [app.ona.com](https://app.ona.com) to trigger the update, or manually set the **Ona URL** to `https://app.ona.com`
The extension is [open source](https://github.com/gitpod-io/browser-extension).
# CLI
Source: https://ona.com/docs/ona/integrations/cli
Manage environments, SSH access, and automations from your terminal.
Manage environments from your terminal - create, start, stop, SSH into environments, and run automations.
## Installation
### Homebrew (macOS and Linux)
```bash theme={null}
brew install gitpod-io/tap/ona
```
The formula auto-detects your OS and architecture. Updates are handled by `brew upgrade ona`.
### macOS and Linux
```bash theme={null}
curl -o ona -fsSL "https://app.gitpod.io/releases/cli/stable/gitpod-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/;s/\(arm64\|aarch64\)/arm64/')" && \
chmod +x ona && \
sudo mv ona /usr/local/bin
```
### Direct download
| Platform | Downloads |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| macOS | [x86\_64](https://app.gitpod.io/releases/cli/stable/gitpod-darwin-amd64) \| [arm64](https://app.gitpod.io/releases/cli/stable/gitpod-darwin-arm64) |
| Linux | [x86\_64](https://app.gitpod.io/releases/cli/stable/gitpod-linux-amd64) \| [arm64](https://app.gitpod.io/releases/cli/stable/gitpod-linux-arm64) |
| Windows | [x86\_64](https://app.gitpod.io/releases/cli/stable/gitpod-windows-amd64.exe) \| [arm64](https://app.gitpod.io/releases/cli/stable/gitpod-windows-arm64.exe) |
After downloading, make the binary executable and move it to your PATH:
```bash theme={null}
chmod +x ona
sudo mv ona /usr/local/bin
```
If macOS shows a security warning, approve the app in **System Settings → Privacy & Security**, or run:
```bash theme={null}
xattr -d com.apple.quarantine ona
```
**Verified installation**
Use SLSA verification during initial installation:
```bash theme={null}
curl -fsSL https://app.gitpod.io/releases/cli/install.sh | VERIFY_SLSA=true bash
```
Requirements: `curl`, `jq`, `awk`, `base64`, and either `sha256sum` or `shasum`. Legacy releases also require `tar`.
If SLSA verification fails, the installation aborts with an error. There is no fallback to an unverified download.
**[SLSA](https://slsa.dev) verification behavior**
Use the verified installer above for both supported release layouts. It verifies legacy `packageHash` attestations and schema-v1 per-platform provenance with a pinned, checksummed Cosign binary before installing the CLI.
**Checksum verification**
Get the expected checksum:
```bash theme={null}
curl -sL https://app.gitpod.io/releases/cli/stable/manifest.json | jq -r '.downloads[""].digest'
```
Calculate your file's checksum and compare:
```bash theme={null}
shasum -a 256 ona
```
## Authentication
### Browser login
```bash theme={null}
ona login
```
Opens your browser to authenticate and stores credentials locally.
### Personal access token
For CI/CD pipelines and scripts, use a [personal access token](/docs/ona/integrations/personal-access-token):
```bash theme={null}
ona login --token "your-token-here"
```
Or set the environment variable:
```bash theme={null}
export ONA_TOKEN="your-token-here"
ona login
```
### Inside Ona environments
The CLI is pre-installed and automatically authenticated with limited access. Run `ona login` to upgrade to full access.
When running inside an environment, the CLI automatically detects the current environment context. This means:
* **Environment ID is inferred**: Commands like `ona environment task`, `ona environment service`, `ona environment port`, and other environment-specific commands work without requiring `--environment-id`
* **Context preserved after login**: When you run `ona login` inside an environment, the environment ID is preserved in your CLI context (as long as the login host matches the environment's host). This allows you to continue using environment-specific commands after authentication.
```bash theme={null}
# Inside an environment - no --environment-id needed
ona environment service list
ona environment port open 3000
# After running ona login, these still work without --environment-id
ona login
ona environment task start my-task
```
If you log into a different host than your environment (e.g., logging into `app.gitpod.io` from an environment on `ona.e-corp.com`), the environment ID will not be preserved.
`ona environment port open` defaults to creator-only access. On a runner that cannot enforce private access, an implicit open falls back to public access with a warning. Pass `--admission creator_only` to fail closed, or `--admission everyone` when an unauthenticated URL is required.
## Common commands
| Command | Description |
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `ona whoami` | Show current user and access level |
| `ona environment list` | List your environments |
| `ona environment list --search ` | Search environments by ID, name, repository URL, or branch |
| `ona environment create ` | Create a new environment |
| `ona environment create --inactivity-timeout 1h` | Create an environment with a custom auto-stop timeout |
| `ona environment update --name ""` | Rename an environment |
| `ona environment update --inactivity-timeout 3h` | Update an environment's auto-stop timeout |
| `ona environment start ` | Start an environment |
| `ona environment stop ` | Stop an environment |
| `ona environment delete ` | Delete an environment |
| `ona environment ssh ` | SSH into an environment |
| `ona environment logs ` | View environment logs |
| `ona environment keep-alive` | [Keep environment alive](/docs/ona/organizations/policies/environment-timeout#keep-environment-alive-during-long-running-tasks) while a process runs |
Use `-o json` or `-o yaml` for machine-readable output.
### Using partial environment IDs
Instead of typing full UUIDs, you can use any substring of an environment ID:
```bash theme={null}
# Full UUID
ona environment ssh 019194a6-f0b0-70a1-beae-99718c351b04
# Prefix
ona environment ssh 019194a6
# Suffix
ona environment ssh 351b04
# Any substring
ona environment ssh 70a1-beae
```
The CLI resolves the partial ID if it uniquely identifies an environment. If the substring matches multiple environments, you'll see an error listing all matching IDs. If no environments match, you'll be prompted to run `ona environment list` to see available environments.
### Using environment names
Give an environment a memorable name when you do not want to copy its UUID:
```bash theme={null}
# Rename an environment
ona environment update 019194a6 --name "api-dev"
# Use the name after renaming
ona environment ssh api-dev
ona environment port list api-dev
ona environment task start build --environment-id api-dev
```
Most user-facing environment commands accept an environment ID, a unique partial ID, or an exact environment name. Name matching is case-insensitive.
To clear a custom name, pass an empty value:
```bash theme={null}
ona environment update api-dev --name ""
```
Use `--inactivity-timeout` on `create` or `update` to set a custom auto-stop timeout. See [auto-stop timeout](/docs/ona/organizations/policies/environment-timeout) for details.
Names are not required to be unique. If a name matches more than one environment, the CLI asks you to use an environment ID instead.
Search across environment IDs, names, repository URLs, and branches with:
```bash theme={null}
ona environment list --search api-dev
```
## SSH access
Configure SSH for direct access:
```bash theme={null}
ona environment ssh-config
```
Then connect using:
```bash theme={null}
ssh .ona.environment
```
Generated SSH aliases and stored CLI contexts use environment IDs, not names. This keeps them stable if an environment is renamed.
On macOS, configure SSH and add an environment to Codex with one command:
```bash theme={null}
ona env codex
```
The command refreshes the standard Ona SSH configuration and adds the environment's workspace directory to Codex as a remote project. It writes `$CODEX_HOME/codex-app/config.json` (usually `~/.codex/codex-app/config.json`), a Codex Desktop remote-setup payload containing the selected environment, then asks the app to apply it and connect through a Codex-specific SSH alias. The payload replaces any previous payload, but applying it preserves other remote connections and projects already stored by Codex Desktop.
The command does not change your normal Codex settings in `$CODEX_HOME/config.toml` (usually `~/.codex/config.toml`) or `environments.toml`.
The environment must be running with its workspace directory available. The generated Codex alias does not start stopped environments; start the environment before reconnecting if it has stopped. The `codex` command must be installed and authenticated in the environment.
You can also use partial environment IDs or environment names with the `ona environment ssh` command:
```bash theme={null}
# Connect using a prefix instead of the full UUID
ona environment ssh 019194a6
# Or use any unique substring
ona environment ssh beae-997
# Or use an exact environment name
ona environment ssh api-dev
```
For file transfers, use the `-O` flag:
```bash theme={null}
scp -O .ona.environment:/workspaces/project/file.txt ./local-file.txt
```
## Port management
```bash theme={null}
ona environment port list
ona environment port list api-dev
ona environment port open --name "my-service"
ona environment port close
```
## Automation commands
```bash theme={null}
ona environment config init
ona environment config apply .ona/config.yaml
ona environment task list
ona environment task start
ona environment task logs
ona environment service list
ona environment service start
```
Use `--environment-id ` to target a specific environment from outside that environment.
## Prebuild and warm pool commands
```bash theme={null}
# List prebuilds for a project
ona prebuild list --project-id
# Trigger a prebuild
ona prebuild trigger
# List all warm pools in the organization
ona prebuild warm-pool list
# List warm pools for a specific project
ona prebuild warm-pool list --project-id
# Create a warm pool (project admin required)
ona prebuild warm-pool create --environment-class-id --min-size 1 --max-size 2
# Get warm pool details
ona prebuild warm-pool get
# Update pool scaling bounds
ona prebuild warm-pool update --min-size 1 --max-size 3
# Delete a warm pool
ona prebuild warm-pool delete
```
See [Warm Pools](/docs/ona/projects/warm-pools) for configuration and auditing details.
## Webhook commands
```bash theme={null}
ona webhook create --name "My Webhook" --type repository --scope "owner/repo" --provider github
ona webhook secret get
```
See [Webhooks](/docs/ona/automations/webhooks) for setup details and SCM registration.
## Dotfiles management
Manage your dotfiles configuration directly from the CLI:
```bash theme={null}
# View current dotfiles configuration
ona user dotfiles get
# Set dotfiles repository
ona user dotfiles set --repository https://github.com/user/dotfiles
# Clear dotfiles configuration
ona user dotfiles set
```
The `get` command supports output formats:
```bash theme={null}
ona user dotfiles get -o json
ona user dotfiles get -o yaml
```
See [dotfiles documentation](/docs/ona/configuration/dotfiles/overview) for more information about using dotfiles with Ona.
## Project and group management
```bash theme={null}
ona project list
ona project create
ona group list
ona group create --name "Team Name"
```
## Configuration
The CLI stores configuration at `~/.ona/configuration.yaml`.
```bash theme={null}
ona config context list
ona config context use
ona config set --autoupdate=true
ona config set --verify-slsa=true
ona config set --release-channel=latest
ona config set --organization-id=
```
## Shell completion
```bash theme={null}
# Bash
ona completion bash > /etc/bash_completion.d/ona
# Zsh
ona completion zsh > "${fpath[1]}/_ona"
# Fish
ona completion fish > ~/.config/fish/completions/ona.fish
```
## Updates
```bash theme={null}
ona version
ona version update
```
### SLSA verification for updates
Enable cryptographic verification of CLI updates to ensure binary integrity:
**Per-update verification:**
```bash theme={null}
ona version update --verify-slsa
```
**Persistent config:**
```bash theme={null}
ona config set --verify-slsa=true
ona version update # Now uses verification by default
```
The `--verify-slsa` flag takes precedence over the config value when explicitly set.
If SLSA verification fails, the update aborts with an error. There is no fallback to unverified download - this ensures you're always notified of potential tampering.
Run `ona help` or add `--help` to any command for more information.
## Troubleshooting
```bash theme={null}
ona login --non-interactive # For headless environments
ona login --token "" # Use token directly
```
If you see `too many authentication failures`, add to `~/.ssh/ona/config`:
```
Host *.ona.environment
IdentitiesOnly yes
```
Debug with:
```bash theme={null}
ssh -vvv .ona.environment
```
# Atlassian
Source: https://ona.com/docs/ona/integrations/configure-atlassian
Connect agents to Jira and Confluence so they can manage issues, search documentation, and stay in sync with your workflow.
Connect Atlassian so agents can create Jira issues, search Confluence pages, and link code changes to tickets.
## What agents can do with Atlassian
Once connected, agents can:
* **Manage Jira issues**: Create, update, and transition issues with relevant context from your codebase.
* **Search Confluence**: Find documentation, design specs, and runbooks without leaving your session.
* **Link code to work**: Associate pull requests and code changes with Jira tickets automatically.
* **Add comments**: Document findings, link PRs, or note blockers directly in Jira issues.
## Example workflows
```
"Create a Jira issue for this authentication bug with the stack trace"
"Search Confluence for the API rate limiting design doc"
"Move issue PROJ-456 to In Progress and add a comment that I'm starting work"
"Find any existing Jira issues about database timeouts before I create a new one"
```
## Connect Atlassian
### Step 1: Atlassian admin configuration
Atlassian requires org admins to explicitly allowlist domains that can connect via MCP. Without this, users will see a cryptic error: **"Your organization admin must authorize access from a domain to this site"**.
An Atlassian organization admin needs to allowlist Ona's domain first:
1. Go to [admin.atlassian.com](https://admin.atlassian.com) > **AI settings** > **Rovo MCP server**
2. Add `https://app.gitpod.io/**` to **"Your domains"**
### Step 2: Organization setup
An Ona organization admin needs to enable Atlassian for your organization.
1. Go to **Organization Settings** > **Integrations**
2. Find Atlassian and click **Enable**
3. Configure default site and project settings if needed
### Step 3: Authenticate your account
Once enabled, connect your personal Atlassian account:
1. Go to **User Settings** > **Integrations**
2. Click **Connect** next to Atlassian
3. Authorize Ona to access your Atlassian site
4. Select which sites to connect
## Verify it works
Start a session with an agent and try:
```
Show me my open Jira issues
```
If you see your issues, you're connected. If not, verify both organization enablement and your personal authentication are complete.
## Tips for effective use
**Be specific about projects**: If you have multiple Jira projects, specify which one: "Create an issue in the API project for this bug."
**Include context**: The more context you give, the better the issue: "Create a Jira issue for this null pointer exception, include the stack trace and the user flow that triggers it."
**Use with AGENTS.md**: Add your Atlassian conventions to AGENTS.md so agents know your project keys, issue types, and workflow stages.
## Next steps
* [Teach agents your codebase](/docs/ona/agents-md) including your Atlassian conventions
* [Organization-level skills](/docs/ona/skills) for common Atlassian workflows like `/bug-report`
* [Learn about integrations](/docs/ona/integrations/overview) for other available connections
## Troubleshooting
Your Atlassian organization admin has not allowlisted Ona's domain for MCP access. Ask them to go to [admin.atlassian.com](https://admin.atlassian.com) > **AI settings** > **Rovo MCP server** and add `https://app.gitpod.io/**` to **"Your domains"**.
Atlassian accounts can have access to multiple sites. Ensure you authorized access to the correct site during the OAuth flow. You can disconnect and reconnect to update your site selection.
# Codex
Source: https://ona.com/docs/ona/integrations/configure-codex
Connect your ChatGPT account so Codex sessions in Ona can use your ChatGPT plan.
Available on the Core plan. ChatGPT plan connections for Codex are currently supported on Ona Cloud only. [Contact sales](https://ona.com/contact/sales) to learn more.
Connect Codex when you want the Codex agent in Ona to use your ChatGPT plan for model requests. You can use Codex without this integration; without it, Codex uses the model access available to your organization.
This page covers the ChatGPT connection. For the agent itself, see [Codex Agent](/docs/ona/agents/codex).
The running environment still consumes OCUs, but Codex model requests that use your ChatGPT plan are not billed by Ona.
## How Codex uses your ChatGPT plan
Codex runs inside the same isolated Ona Cloud environments as other agents. It can read your repository, use configured tools, run commands, and open pull requests while following your organization's policies.
After you connect your ChatGPT account, the Codex agent uses your ChatGPT plan for model requests. The connection changes model billing and limits only. Ona still provisions and meters the environment that Codex works in.
## Prerequisites
* Your organization is on the Core plan.
* Your organization uses Ona Cloud.
* An organization admin enabled the Codex integration.
* You have a ChatGPT account with Codex access.
If Codex is not listed under **User Settings > Integrations** or the service account's **Integrations** section, ask an organization admin to enable it or contact Ona support.
## Connect your ChatGPT account
1. Go to [User Settings > Integrations](https://app.ona.com/?user-settings=integrations).
2. Find **Codex**.
3. Click **Connect**.
4. Ona opens the OpenAI device authorization page and copies a one-time code.
5. Sign in to ChatGPT, enter the code, and approve the authorization.
6. Return to Ona. The dialog updates when the account is connected.
## Connect Codex for a service account
Connect Codex to a service account when automations running as that service account should use a ChatGPT plan.
1. Go to **Settings > Members > Service Accounts**.
2. Open the service account.
3. In **Integrations**, find **Codex**.
4. Click **Connect**.
5. Ona opens the OpenAI device authorization page and copies a one-time code.
6. Sign in to ChatGPT, enter the code, and approve the authorization.
7. Return to Ona. The dialog updates when the account is connected.
## Use Codex in Ona
Start an environment, open the conversation menu, and choose **Codex** when it is available. If you connected your ChatGPT account, Codex uses your ChatGPT plan for model requests from your user session. If a service account has a Codex connection, automations running as that service account can use that connection.
If you disconnect the integration, future Codex sessions for that user or service account fall back to the model access available to your organization.
## Billing and limits
* OpenAI manages ChatGPT plan usage. Ona does not charge OCUs for Codex model requests that use your connected ChatGPT account.
* Ona still charges for the environment while it is running. See [Cost & Budgets](/docs/ona/billing/usage).
* If ChatGPT rate limits or usage limits are reached, Codex can pause or fail until the limit resets or your ChatGPT plan changes.
## Disconnect Codex
1. Go to [User Settings > Integrations](https://app.ona.com/?user-settings=integrations), or open the service account details page.
2. Find **Codex**.
3. Click **Disconnect**.
## Troubleshooting
The integration is not enabled for your organization yet. Ask an organization admin to check **Organization Settings > Integrations**, or contact Ona support.
Close the dialog and click **Connect** again to start a new authorization flow.
If you completed OpenAI Trusted Access for Cyber verification after connecting Codex to Ona, disconnect Codex and connect it again. Sign in with the same ChatGPT account you verified, then start a new Codex conversation.
Reconnecting starts a new OpenAI authorization and replaces the saved credentials. OpenAI may still block some requests after verification. If the error continues, review [OpenAI's Daybreak troubleshooting guide](https://help.openai.com/en/articles/20001259-openai-daybreak-common-issues-and-troubleshooting).
The connected ChatGPT account has likely reached a Codex limit set by OpenAI. Check your ChatGPT plan and billing details, then retry after the limit resets.
# GitHub
Source: https://ona.com/docs/ona/integrations/configure-github
Enable the GitHub integration for one or more GitHub organizations.
This page is for the organization admin who enables the GitHub integration. For end-user usage, see [Mention Ona on a pull request](/docs/ona/integrations/github-pr-mentions).
The GitHub integration uses the Ona GitHub App. It is separate from [GitHub source control](/docs/ona/source-control/github), which configures repository access for environments.
## Prerequisites
* You are an admin of an Ona organization.
* You use GitHub.com. For GitHub Enterprise Server, use a [webhook event source](/docs/ona/automations/webhooks) for pull request triggers.
* You have admin rights on the GitHub.com organization (or personal account) where the App will be installed.
## Enable GitHub
1. In Ona, go to **Organization Settings** > **Integrations**.
2. Find **GitHub** and turn on the switch.
3. GitHub opens. Choose the organization (or your personal account) to install the App on.
4. Choose which repositories the App can access:
* **All repositories**: the App can be mentioned on every PR in the org.
* **Only select repositories**: pick a subset. You can change this later from GitHub.
5. Approve the permissions request and finish the install on GitHub.
6. Ona shows the enabled status on the integration page.
## Connect another GitHub organization
Connect each GitHub organization that owns repositories you want to use with Ona.
1. In Ona, go to **Organization Settings** > **Integrations**.
2. Find **GitHub** and click the ellipsis button to open **GitHub organizations**.
3. Click **Install into another GitHub organization**.
4. In GitHub, choose the organization and the repositories the App can access.
5. Approve the permissions request and finish the install.
6. Return to Ona. The organization appears in the **GitHub organizations** dialog.
## Permissions
| Permission | Access | Why |
| ------------- | ------------ | --------------------------------------------------------------------------- |
| Pull requests | Read & write | Read PR metadata and post agent status comments. |
| Issues | Read & write | Read and post comments on PRs. GitHub treats PR comments as issue comments. |
| Contents | Read | Look up the repository associated with a PR. |
| Metadata | Read | Required by GitHub for any App. |
If a permission is missing, Ona posts a `[!CAUTION]` comment on the PR:
> Ask an organization admin to update the Ona GitHub App installation and grant read & write access to **issues** and **pull requests**.
To fix it, open the App in GitHub, accept the new permissions, then ask the user to mention the agent again.
## Verify the installation
1. Open a pull request in a repository the App can access.
2. Post a comment containing `@ona-agent`.
3. Within a few seconds, the agent will react to your comment and post a reply with the running session.
If nothing happens, see [Troubleshooting](/docs/ona/integrations/github-pr-mentions#troubleshooting).
## Change which repositories the App can access
1. Go to your GitHub organization's **Settings** > **GitHub Apps** > **Ona**.
2. Click **Configure**.
3. Under **Repository access**, add or remove repositories.
4. Save. The change takes effect immediately.
## Disable GitHub
Disable a GitHub organization if you want to stop Ona from responding to PR mentions for that organization without uninstalling the App on GitHub (for example, during a migration or incident).
1. In Ona, go to **Organization Settings** > **Integrations**.
2. Find **GitHub** and click the ellipsis button to open **GitHub organizations**.
3. Turn off the switch for the GitHub organization you want to disable.
4. Click **Done**.
While disabled:
* The App stays installed on GitHub and keeps receiving webhook events for that GitHub organization, but Ona ignores them. No new agent sessions start for `@ona-agent` mentions in repositories owned by that organization.
* Other enabled GitHub organizations keep working.
To resume, open **GitHub organizations** and turn the organization's switch back on.
## Uninstall the App
1. Go to your GitHub organization's **Settings** > **GitHub Apps** > **Ona**.
2. Click **Configure**, scroll to **Uninstall**, and confirm.
Uninstalling stops PR mention triggers for that GitHub organization. Sessions already running keep running. New sessions start again only when the App is reinstalled.
## Next steps
* [Mention Ona on a pull request](/docs/ona/integrations/github-pr-mentions): what users do once GitHub is enabled.
* [GitHub source control](/docs/ona/source-control/github): repository access for environments.
* [Integrations overview](/docs/ona/integrations/overview).
# Granola
Source: https://ona.com/docs/ona/integrations/configure-granola
Connect agents to your Granola meeting notes so they can search transcripts, extract action items, and access meeting context.
Connect Granola so agents can search your meetings, read transcripts, and pull in discussion context during sessions.
## What agents can do with Granola
Once connected, agents can:
* **Search meeting notes**: Find meetings by title, date, or attendees across your Granola account.
* **Read transcripts**: Access full meeting transcripts and notes without leaving your session.
* **Extract action items**: Pull out tasks, decisions, and follow-ups from past meetings.
* **Answer questions from meetings**: Ask natural language questions about what was discussed in any meeting.
## Example workflows
```
"Search Granola for the last meeting about the payments service"
"What action items came out of yesterday's standup?"
"Find the meeting where we discussed the database migration plan"
"What did the team decide about the API versioning strategy in last week's design review?"
```
## Connect Granola
### Step 1: Organization setup
An admin needs to enable Granola for your organization first.
1. Go to **Organization Settings** > **Integrations**
2. Find Granola and click **Enable**
3. Configure default settings if needed
### Step 2: Authenticate your account
Once enabled, connect your personal Granola account:
1. Go to **User Settings** > **Integrations**
2. Click **Connect** next to Granola
3. Authorize Ona to access your Granola meeting notes via browser-based OAuth
4. Confirm which meetings and data the integration can access
## Verify it works
Start a session with an agent and try:
```
Search Granola for my recent meetings
```
If you see results from your account, you're connected. If not, verify both organization enablement and your personal authentication are complete.
## Tips for effective use
**Be specific about meetings**: If you have many meetings, give the agent specific details: "Find the meeting with the design team from last Tuesday about the onboarding flow."
**Combine with code context**: Ask the agent to cross-reference meeting decisions with actual code: "What did we agree on for error handling in the meeting last week? Show me the current implementation."
**Use with AGENTS.md**: Add references to recurring meetings or key decisions in AGENTS.md so agents know where to find relevant context from past discussions.
## Next steps
* [Teach agents your codebase](/docs/ona/agents-md) including references to key meeting decisions
* [Organization-level skills](/docs/ona/skills) for common workflows like `/meeting-summary`
* [Learn about integrations](/docs/ona/integrations/overview) for other available connections
## Troubleshooting
You can only query meetings that you own. Shared meetings from other participants are not accessible through the integration. Make sure the meeting you're looking for is in your own Granola account.
Users on Granola's basic plan can only access notes from the last 30 days. If you need older meetings, check your Granola subscription tier.
Granola limits requests to approximately 100 per minute. If you're running into errors during heavy use, wait briefly and try again.
# Linear
Source: https://ona.com/docs/ona/integrations/configure-linear
Connect agents to your project management so they can create issues, update status, and stay in sync with your workflow.
Connect Linear so agents can create issues, update status as they work, and link code changes to tickets.
## What agents can do with Linear
Once connected, agents can:
* **Create issues from context**: Find a bug? The agent creates an issue with steps to reproduce, relevant code snippets, and suggested labels.
* **Update as they work**: Agents can move issues to "In Progress" when they start and "Done" when they finish.
* **Search and reference**: Ask about related issues, find duplicates, or get context from existing tickets.
* **Add comments**: Document findings, link PRs, or note blockers directly in Linear.
## Start a session from an issue
Beyond the MCP tools above, you can start an agent session directly from a Linear issue in two ways:
* **Mention the agent** in an issue comment to start a session on that issue.
* **Delegate the issue** to Ona by assigning it, and the agent picks it up.
The agent reads the issue for context, works in the matching Ona environment, and posts its progress back on the issue. The session runs under your identity, so it uses your organization role and project permissions.
When someone assigns an issue to Ona on another person's behalf, the session runs as the issue's assignee. This requires the agent app authorization from [Step 1](#step-1-organization-setup) to be active. If it is not, see the "Agent features are not active" note under [Troubleshooting](#troubleshooting).
## Example workflows
```
"Create a Linear issue for this authentication bug with the stack trace"
"Show me all high-priority issues assigned to me in the API project"
"Move issue ABC-123 to In Progress and add a comment that I'm starting work"
"Find any existing issues about rate limiting before I create a new one"
```
## Connect Linear
### Step 1: Organization setup
An admin needs to enable Linear for your organization first.
1. Go to **Organization Settings** > **Integrations**
2. Find Linear and click **Enable**
3. Configure default workspace settings if needed
### Step 2: Authenticate your account
Once enabled, connect your personal Linear account:
1. Go to **User Settings** > **Integrations**
2. Click **Connect** next to Linear
3. Authorize Ona to access your Linear workspace
4. Select which workspaces to connect
## Verify it works
Start a session with an agent and try:
```
Show me my open Linear issues
```
If you see your issues, you're connected. If not, verify both organization enablement and your personal authentication are complete.
## Tips for effective use
**Be specific about projects**: If you have multiple Linear teams, specify which one: "Create an issue in the API team for this bug."
**Include context**: The more context you give, the better the issue: "Create an issue for this null pointer exception, include the stack trace and the user flow that triggers it."
**Use with AGENTS.md**: Add your Linear conventions to AGENTS.md so agents know your labeling system and workflow stages.
## Next steps
* [Teach agents your codebase](/docs/ona/agents-md) including your Linear conventions
* [Organization-level skills](/docs/ona/skills) for common Linear workflows like `/bug-report`
* [Learn about integrations](/docs/ona/integrations/overview) for other available connections
## Troubleshooting
This warning means the app authorization for agent capabilities (like @mentions and webhooks) is missing or expired. Basic features like reading and creating issues via MCP tools still work with your personal token.
Click **Authorize app** to start the authorization flow.
Linear allows only one app installation per workspace. If another Ona organization has already authorized the app on the same Linear workspace, the authorization flow will show that the app is already installed instead of issuing a new token.
To resolve this:
1. In Linear, go to **Settings** > **Integrations** > **Ona** and remove the existing installation
2. Return to Ona and click **Authorize app** to re-install for the correct organization
Only one Ona organization can have agent features (webhooks, @mentions) active per Linear workspace at a time. Other Ona organizations connected to the same workspace can still use MCP tools (read/write issues) through personal authentication.
# Notion
Source: https://ona.com/docs/ona/integrations/configure-notion
Connect agents to your Notion workspace so they can search pages, read documentation, and access project context.
Connect Notion so agents can search your workspace, read documentation, and pull in project context during sessions.
## What agents can do with Notion
Once connected, agents can:
* **Search your workspace**: Find pages, databases, and documents across your Notion workspace.
* **Read documentation**: Access design docs, runbooks, and technical specs without leaving your session.
* **Reference project context**: Pull in requirements, meeting notes, and decisions relevant to your current task.
* **Add content**: Create and update pages with findings, notes, or documentation.
## Example workflows
```
"Search Notion for the API design doc for the payments service"
"Find the onboarding runbook in Notion"
"What does the Notion page about our database migration plan say?"
"Create a Notion page summarizing the changes I made to the auth module"
```
## Connect Notion
### Step 1: Organization setup
An admin needs to enable Notion for your organization first.
1. Go to **Organization Settings** > **Integrations**
2. Find Notion and click **Enable**
3. Configure default workspace settings if needed
### Step 2: Authenticate your account
Once enabled, connect your personal Notion account:
1. Go to **User Settings** > **Integrations**
2. Click **Connect** next to Notion
3. Authorize Ona to access your Notion workspace
4. Select which pages and databases to share
## Verify it works
Start a session with an agent and try:
```
Search Notion for our project documentation
```
If you see results from your workspace, you're connected. If not, verify both organization enablement and your personal authentication are complete.
## Tips for effective use
**Be specific about pages**: If you have a large workspace, give the agent specific page or database names: "Find the Q1 planning page in the Engineering space."
**Share the right pages**: During Notion authorization, you select which pages the integration can access. Make sure to share the pages your agents will need.
**Use with AGENTS.md**: Add references to key Notion pages in AGENTS.md so agents know where to find your team's documentation and conventions.
## Next steps
* [Teach agents your codebase](/docs/ona/agents-md) including references to your Notion documentation
* [Organization-level skills](/docs/ona/skills) for common workflows like `/find-docs`
* [Learn about integrations](/docs/ona/integrations/overview) for other available connections
## Troubleshooting
Notion's authorization model requires you to explicitly select which pages to share during the OAuth flow. If the agent can't find a page, disconnect and reconnect, ensuring you share the relevant pages.
Pages must be explicitly shared with the integration during authorization. You can update your page selection by disconnecting and reconnecting the integration.
# Sentry
Source: https://ona.com/docs/ona/integrations/configure-sentry
Connect agents to Sentry so they can view errors, analyze stack traces, and access monitoring context.
Connect Sentry so agents can view errors, analyze stack traces, and use monitoring context to debug issues.
## What agents can do with Sentry
Once connected, agents can:
* **View issues**: Browse and search Sentry issues, including error messages, frequency, and affected users.
* **Analyze stack traces**: Read stack traces and correlate errors with your codebase to identify root causes.
* **Search events**: Find specific errors, filter by release or environment, and track regressions.
* **Add context**: Reference Sentry issues in sessions and link errors to code changes.
## Example workflows
```
"Show me the most frequent unresolved Sentry issues in production"
"What's the stack trace for issue SENTRY-1234?"
"Find any Sentry errors related to the payment processing module"
"Were there any new errors after the last deployment?"
```
## Connect Sentry
### Step 1: Organization setup
An admin needs to enable Sentry for your organization first.
1. Go to **Organization Settings** > **Integrations**
2. Find Sentry and click **Enable**
3. Configure default project settings if needed
### Step 2: Authenticate your account
Once enabled, connect your personal Sentry account:
1. Go to **User Settings** > **Integrations**
2. Click **Connect** next to Sentry
3. Authorize Ona to access your Sentry organization
4. Select which projects to connect
## Verify it works
Start a session with an agent and try:
```
Show me recent Sentry issues in production
```
If you see your issues, you're connected. If not, verify both organization enablement and your personal authentication are complete.
## Tips for effective use
**Be specific about projects**: If you have multiple Sentry projects, specify which one: "Show me errors in the api-server project."
**Include environment context**: Mention the environment when searching: "Find production errors from the last 24 hours."
**Use with AGENTS.md**: Add your Sentry project names and conventions to AGENTS.md so agents know your project structure and alerting conventions.
## Next steps
* [Teach agents your codebase](/docs/ona/agents-md) including your Sentry project conventions
* [Organization-level skills](/docs/ona/skills) for common workflows like `/error-report`
* [Learn about integrations](/docs/ona/integrations/overview) for other available connections
## Troubleshooting
Ensure you authorized access to the correct organization and projects during the OAuth flow. You can disconnect and reconnect to update your project selection.
# Slack
Source: https://ona.com/docs/ona/integrations/configure-slack
Mention Ona in Slack to start and follow agent sessions from a channel or direct message.
Connect Slack so you can start agent sessions from a Slack message and follow the work in the same thread. Mention Ona in a channel or send it a direct message, describe the task, and the agent runs in an Ona environment and replies in place.
## What you can do from Slack
Once connected, you can:
* **Start a session from a channel**: `@Ona` in a channel with a task and a repository link. The agent starts in the matching project's environment and replies in the thread.
* **Start a session from a direct message**: Message Ona directly to work without a channel.
* **Follow along in the thread**: The agent posts one reply that updates in place as it works, with a link to the Ona session and environment.
* **Continue the conversation**: Reply in the same thread to give the agent more instructions. The thread stays tied to one session.
## How it works
* The agent runs under **your identity**, mapped from your linked Slack account. It uses your organization role and project permissions.
* The agent resolves which project to work in from the repository URL in your message. If your message has no repository link, it reuses the project from earlier in the thread, or asks you to pick a project.
* A thread belongs to the user who started it. If someone else mentions Ona in that thread, the agent asks them to start their own thread.
* Editing a message after the agent starts does not change the prompt. Post a new mention to change direction.
## Connect Slack
Connecting Slack takes two steps: an administrator enables it for the organization, then each user links their own Slack account.
### Step 1: Organization setup
An admin needs to enable Slack for your organization first.
1. Go to **Organization Settings** > **Integrations**.
2. Find Slack and click **Enable**.
3. Complete the Slack app installation and authorize it for your workspace.
### Step 2: Authenticate your account
Once enabled, connect your personal Slack account so the agent acts with your permissions:
1. Go to **User Settings** > **Integrations**.
2. Click **Connect** next to Slack.
3. Authorize Ona to link your Slack account.
If you mention Ona before connecting your account, it replies with a **Connect Slack in Ona** link and resumes your request automatically once you finish connecting.
## Verify it works
In a channel where the Ona app is present, or in a direct message, try:
```
@Ona review this repo https://github.com/your-org/your-repo and summarize the README
```
The agent reacts to your message, posts a reply with a link to the running session, and updates that reply as it works. If nothing happens, verify both organization enablement and your personal account link are complete.
## Tips for effective use
**Include a repository link**: The agent picks the project from the repository URL in your message. Without one, it falls back to the thread's earlier project or asks you to choose.
**Keep one task per thread**: Each thread maps to a single session. Start a new thread for a new task.
**Use with AGENTS.md**: Add your project conventions to [AGENTS.md](/docs/ona/agents-md) so agents follow your workflow.
## Next steps
* [Integrations overview](/docs/ona/integrations/overview) for other available connections.
* [Projects](/docs/ona/projects/overview): required so the agent knows where to run.
* [AGENTS.md](/docs/ona/agents-md): teach agents your codebase and conventions.
## Troubleshooting
Check, in order:
1. Is Slack enabled for your organization in **Organization Settings** > **Integrations**?
2. Have you linked your Slack account in **User Settings** > **Integrations**?
3. Is the Ona app present in the channel? In a private channel, invite the app first.
4. Did you mention `@Ona` (in a channel) or message it directly?
Ona could not map your Slack account to an Ona user. Open the **Connect Slack in Ona** link in the reply, finish connecting your account, and the agent resumes your original request.
The agent could not find an Ona project for the repository, or the project has no environment class configured. Create a [project](/docs/ona/projects/overview) for the repository, set an environment class in its settings, and mention Ona again.
# Mention Ona on a pull request
Source: https://ona.com/docs/ona/integrations/github-pr-mentions
Mention @ona-agent in a GitHub pull request comment to start an agent on the PR.
Available on the Core plan. [Contact sales](https://ona.com/contact/sales) to enable it for Enterprise.
Mention `@ona-agent` in a pull request comment to start an agent on that PR. The agent reads the PR diff and recent comments, then works on the task you describe.
For setup, see [GitHub](/docs/ona/integrations/configure-github).
## How it works
* The agent runs under **your identity**, mapped from your linked GitHub login. It uses your organization role and project permissions. Commits and PRs the agent opens are attributed to you.
* The Ona GitHub App posts the reactions and reply comments. Your account needs no extra permissions for that.
* The agent sees the PR title, body, diff, and recent comments. Its access to the rest of the repository is governed by the [project](/docs/ona/projects/overview) at runtime.
* Pull requests from forks are ignored. Fork PRs can carry untrusted code, and anyone with a GitHub account can comment on them.
* Per-organization rate limits apply.
## Prerequisites
* The [GitHub integration](/docs/ona/integrations/configure-github) is enabled for the GitHub organization that owns the repository.
* The repository is in the App's selected repositories.
* An Ona [project](/docs/ona/projects/overview) exists for the repository. If one does not, the agent prompts you to create one.
## Where you can mention
The agent responds to mentions in three places on a pull request:
| Surface | Where it appears |
| ------------------------- | -------------------------------------------------------------------------------------------------------------- |
| **PR comment** | The main conversation tab. Triggered by `issue_comment` events. |
| **Inline review comment** | A comment attached to a specific line in the diff. Triggered by `pull_request_review_comment` events. |
| **Review submission** | The body of a submitted review (Approve, Request changes, Comment). Triggered by `pull_request_review` events. |
Mentions in regular issues and on fork PRs are ignored.
## Supported handles
Use `@ona-agent` to trigger the agent.
Mentions inside fenced code blocks, inline code spans, blockquotes, HTML comments, and image syntax are ignored, so you can write about the handle without triggering it.
## Examples
### Request a code review
A comment with only the handle starts a review:
```
@ona-agent
```
The agent runs with the prompt `Review this PR and help with any issues.`
### Mention with a task
Anything after the handle becomes the agent's prompt:
```
@ona-agent please add unit tests for the new pricing function
```
```
@ona-agent the snapshot test on line 42 is failing, figure out why and fix it
```
### Reply on a review thread
If you mention the agent in a reply to an inline review comment, the agent receives the surrounding thread as context.
## Commands
`@ona-agent retry` replays the last failed agent start on this PR. Use it after fixing the cause (for example, after creating a missing project).
The command must be the whole prompt. `@ona-agent retry the deploy` runs as a normal prompt.
## What you'll see
1. The agent reacts to your comment with an emoji to confirm the trigger.
2. It posts one reply with the running session and a link to the Ona session view.
3. The same reply updates in place as the agent works.
## Cancelling
To cancel a running session from GitHub:
* **Delete your trigger comment.** Cancels the session and posts a confirmation.
* **Delete the PR's head branch.** Cancels the session.
You can also cancel from the Ona session view.
## Limitations
* The agent reads the PR diff and the most recent comments. Older comments are not included.
* Fork PRs are not supported. See [How it works](#how-it-works).
* Editing a comment after the agent starts does not change the prompt. To change direction, post a new `@ona-agent` comment.
* Posting a second `@ona-agent` mention while the first session is still running is not guaranteed to queue. Wait for the first reply, or cancel the running session by deleting the trigger comment.
* Available on the Core plan. [Contact sales](https://ona.com/contact/sales) to enable it for Enterprise.
## Next steps
* [GitHub](/docs/ona/integrations/configure-github): enable and manage the integration.
* [Projects](/docs/ona/projects/overview): required so the agent knows where to run.
* [Integrations overview](/docs/ona/integrations/overview).
## Troubleshooting
Check, in order:
1. Is the [GitHub integration](/docs/ona/integrations/configure-github) enabled for the repository's owner?
2. Is the repository in the App's selected repositories?
3. Is your Ona organization on the Core plan?
4. Did you spell the handle correctly (`@ona-agent`)?
5. Are you commenting on a **pull request**, not a regular issue?
6. Is the PR from the same repository, not a fork?
If all six check out and the agent stays silent for a minute or two, contact support.
The agent posted a `[!CAUTION]` comment because the App is missing a required permission. Ask an admin to update the GitHub installation. See [Permissions](/docs/ona/integrations/configure-github#permissions).
No Ona project is configured for this repository. The agent posts a link to create one. Once you create it, the agent resumes the original mention. If you do not create the project within a few minutes, the watcher times out and you'll need to mention the agent again.
# Open from URL
Source: https://ona.com/docs/ona/integrations/ona-url
Create environments directly from a repository URL.
Create an environment by prefixing any repository URL with `https://app.ona.com/#`:
```
https://app.ona.com/#
```
This provides an alternative to the [browser extension](/docs/ona/integrations/browser-extension). To embed the link in a repository README, see the [README button](/docs/ona/integrations/readme-button) guide.
## Examples
| Provider | URL |
| --------- | ------------------------------------------------------------ |
| GitHub | `https://app.ona.com/#https://github.com/gitpod-io/empty` |
| GitLab | `https://app.ona.com/#https://gitlab.com/gitpod-io/empty` |
| Bitbucket | `https://app.ona.com/#https://bitbucket.org/gitpod-io/empty` |
## Runner and environment class
When you open a repository, you'll be prompted to choose a runner and environment class.
To set defaults, create a [Project](/docs/ona/projects/overview) with your preferred configuration. Projects are automatically selected when users open that repository.
# Integrations
Source: https://ona.com/docs/ona/integrations/overview
Connect Ona to source control, work trackers, docs, incident tools, and cloud providers.
Ona integrations fall into three categories:
* **Source control** for cloning repositories, pushing commits, and letting agents interact with pull requests and issues
* **Tool integrations** for giving agents access to work trackers, docs, incident tools, and other MCP-backed services
* **Cloud access** for federating from environments into providers like AWS without long-lived credentials
This page is the overview. Use the linked setup guides for provider-specific steps.
## Source control
Source control is the foundational integration in Ona. It gives environments access to your repositories and lets agents work with the same permissions your developers already have.
* [Source control overview](/docs/ona/source-control/overview)
* [GitHub & GitLab agent tools](/docs/ona/agents/scm-tools)
Supported providers:
| Provider | Repo access | Agent API tools |
| ------------------------------------------------ | ----------- | --------------- |
| [GitHub](/docs/ona/source-control/github) | Yes | Yes |
| [GitLab](/docs/ona/source-control/gitlab) | Yes | Yes |
| [Bitbucket Cloud](/docs/ona/source-control/bitbucket) | Yes | No |
| [Azure DevOps](/docs/ona/source-control/azuredevops) | Yes | No |
## Tool integrations for agents
Most non-SCM integrations are exposed to agents through the [Model Context Protocol (MCP)](/docs/ona/mcp). There are two distinct layers, and both must be in place before an agent can use a tool:
* **Organization integrations** are configured by an administrator in your organization settings. They turn an integration on for the org (e.g., "Linear is allowed in this organization") and provide the OAuth client and any shared configuration. Without this, the integration does not appear to users.
* **Principal authentication** happens after the org integration is enabled. Users connect personal accounts from **User Settings > Integrations**. Service accounts connect from the service account details page so automations can run with service-account credentials.
In short:
1. **Organization-level enablement** by an administrator
2. **User or service-account authentication** so the agent acts with the right identity
Available integrations:
| Integration | What agents can do | Setup |
| ----------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| Linear | Read issues, update status, use backlog context, and start sessions from an issue | [Configure Linear](/docs/ona/integrations/configure-linear) |
| Slack | Mention Ona to start and follow agent sessions from a channel or DM | [Configure Slack](/docs/ona/integrations/configure-slack) |
| Atlassian | Work with Jira and Confluence | [Configure Atlassian](/docs/ona/integrations/configure-atlassian) |
| Notion | Search and read workspace docs | [Configure Notion](/docs/ona/integrations/configure-notion) |
| Sentry | Inspect errors and issue context | [Configure Sentry](/docs/ona/integrations/configure-sentry) |
| Granola | Search meeting notes and transcripts | [Configure Granola](/docs/ona/integrations/configure-granola) |
| GitHub | Mention `@ona-agent` on a pull request to start an agent on the PR | [Configure GitHub](/docs/ona/integrations/configure-github) |
To check status during a session, open the **MCP Integrations** panel in the prompt input.
## Cloud access
Ona environments can also federate into cloud providers using short-lived credentials instead of static secrets.
* [OpenID Connect (OIDC)](/docs/ona/configuration/oidc) for the core model
* [AWS access from Ona](/docs/ona/integrations/aws) for the AWS-specific setup
GCP follows the same OIDC pattern described in the OIDC guide.
## Related tools
Some things that used to get lumped in as "integrations" are better understood as developer interfaces or launch methods:
* [CLI](/docs/ona/integrations/cli)
* [Ona SDK](/docs/ona/integrations/sdk)
* [Personal access tokens](/docs/ona/integrations/personal-access-token)
* [Browser extension](/docs/ona/integrations/browser-extension)
* [Open from URL](/docs/ona/integrations/ona-url)
* [README button](/docs/ona/integrations/readme-button)
* [Port sharing](/docs/ona/integrations/ports)
# Port sharing
Source: https://ona.com/docs/ona/integrations/ports
Expose ports from environments to share running services.
Expose ports from your Ona environment to share running services with teammates, test webhooks, or preview work without deploying.
## How it works
When you open a port, Ona creates a URL with automatic TLS termination. All shared URLs use HTTPS. You can configure whether Ona connects to your service via HTTP (default) or HTTPS.
If the runner supports port authentication, each open port also has an access level that controls who can reach the URL. You may need to upgrade the runner before those access controls are available. Until then, shared ports behave like `everyone`.
| Deployment | Access |
| ------------------ | -------------------------------------------------------------------------------------------------------------------- |
| Ona Cloud | Shared URLs are reachable on Ona's network. Port admission can still require organization or creator authentication. |
| Enterprise Runners | Through your runner's Network Load Balancer, controlled by your network configuration and the port's admission level |
## Prerequisites
Services must:
* Listen on `0.0.0.0` (not `localhost` or `127.0.0.1`)
* Use the [host network stack](#host-network-stack) if running inside a container
```javascript theme={null}
app.listen(3000, '0.0.0.0', () => {
console.log('Server running on port 3000');
});
```
## Open ports
Open ports are accessible according to the port's configured admission level, your organization policy, and your runner network configuration.
If access controls are unavailable in the dashboard, the runner may need an upgrade before it supports port authentication. For access level definitions and policy caps, see [Port sharing policy](/docs/ona/organizations/policies/port-sharing#port-access-levels).
### Open a port in the dashboard
1. Open the environment details page and go to **Ports**.
2. Select **Add port**.
3. Enter the port number and optional name.
4. Choose **HTTP** or **HTTPS**.
5. If available, choose an **Access** level.
If your organization caps the maximum admission level, options above the cap appear as **restricted by policy** in the access dropdown. See [Maximum port admission level](/docs/ona/organizations/policies/port-sharing#maximum-port-admission-level).
### Open a port in VS Code
1. In the Ona view, expand **Ports**.
2. Select **Open Port**.
3. Enter a port name and number.
VS Code desktop and VS Code Browser open the port for the environment creator by default. If the runner is too old to enforce private access, VS Code opens the port for everyone instead and shows a warning.
The VS Code command cannot request public access explicitly. If you need an unauthenticated URL for a webhook or callback, use `ona environment port open --admission everyone`.
### Open a port from the CLI
By default, the CLI opens the port for the environment creator only. If the runner is too old to enforce private access, the CLI opens the port for everyone instead and prints a warning to stderr. For admission level definitions, see [Port access levels](/docs/ona/organizations/policies/port-sharing#port-access-levels).
```bash theme={null}
# Use the private-first default
ona environment port open 3000 --name my-app
# Require private access and fail instead of falling back on an older runner
ona environment port open 3000 --name my-app --admission creator_only
# Share with other members of your organization
ona environment port open 3000 --admission organization
# Request unauthenticated access and tell Ona to use HTTPS to your service
ona environment port open 8443 --protocol https --admission everyone
# Review or close shared ports
ona environment port list
ona environment port close 3000
```
Scripts created before this default changed may expect an unauthenticated URL. If unauthenticated access is part of the script's contract, such as a webhook callback, add `--admission everyone` explicitly.
## Access denied and retry
When a shared port needs authentication, the browser is sent through Ona's `/auth/port/start` flow before loading the port URL. This flow establishes or refreshes the browser's port-access session and then returns the user to the requested port.
If access is still not allowed, Ona shows **Port Access Denied** and explains why. Common reasons include:
* The port is shared as `creator_only` or `organization`, and your identity does not satisfy that access level.
* Your organization policy blocks the port's current sharing level.
* The runner needs an upgrade before it can enforce port access control.
Use **Retry** after you sign in, switch to the correct organization, or after the port owner or an admin changes the port admission or policy. Retry reruns `/auth/port/start` with the original environment and port parameters.
## Services that only listen on localhost
Some tools hardcode `localhost` as their bind address with no option to change it. AWS SSM port forwarding (`session-manager-plugin`) is a common example. Since Ona's port-sharing proxy connects from outside the loopback interface, these services return "Service Unavailable" (503) when accessed through a shared port URL.
Two workarounds are available:
### Option A: iptables (no extra packages)
Use kernel-level NAT to redirect incoming traffic to the loopback address. This is already available in the environment and lets you keep the same port number.
```bash theme={null}
# Allow routing to loopback addresses (off by default)
sudo sysctl -w net.ipv4.conf.all.route_localnet=1
# Redirect external traffic on port 6767 to localhost:6767
sudo iptables -t nat -A PREROUTING -p tcp --dport 6767 -j DNAT --to-destination 127.0.0.1:6767
# Open the port in Ona
ona environment port open 6767 --name "my-service"
```
### Option B: socat (userspace relay)
Use `socat` to relay traffic from `0.0.0.0` on a second port to the localhost-bound service. Requires installing `socat` (`apt-get install -y socat`) but does not need root.
```bash theme={null}
# Relay from 0.0.0.0:6768 to localhost:6767
socat TCP-LISTEN:6768,fork,reuseaddr,bind=0.0.0.0 TCP:127.0.0.1:6767
# Open the relayed port in Ona (note: different port number)
ona environment port open 6768 --name "my-service"
```
## Host network stack
By default, the Dev Container network is isolated from the VM. For port sharing to work, services must be accessible on the host network. There are several scenarios to consider:
### Dev Container network mode
To make your Dev Container itself use the host network stack, configure your `devcontainer.json`:
**Single container setup:**
```json theme={null}
{
"name": "My Project",
"image": "mcr.microsoft.com/devcontainers/javascript-node:20",
"runArgs": ["--network=host"]
}
```
**Multi-container setup (Docker Compose):**
See [Multi-container development](/docs/ona/configuration/devcontainer/overview#multi-container-development) for complete setup. The key requirement is `network_mode: host` on all services:
```yaml theme={null}
# docker-compose.yml
services:
app:
build: .
network_mode: host
command: sleep infinity
db:
image: postgres:16
network_mode: host
environment:
POSTGRES_PASSWORD: postgres
```
### Containers inside Dev Container (Docker-in-Docker)
When running containers inside your Dev Container using Docker-in-Docker, those containers must also share the host network namespace. Otherwise, ports are only accessible within Docker's bridge network and Ona cannot forward them.
**Docker run:**
```bash theme={null}
# ✗ Won't work - port only accessible on Docker bridge network
docker run -d -p 8080:8080 myapp
# ✓ Works - port accessible to Ona for forwarding
docker run -d --network host myapp
```
**Docker Compose inside Dev Container:**
```yaml theme={null}
services:
database:
image: postgres:16
network_mode: host
environment:
POSTGRES_PASSWORD: postgres
redis:
image: redis:7
network_mode: host
```
Without `network_mode: host` or `--network host`, services use Docker's bridge network. Ports mapped with `-p` or `ports:` are only accessible within that bridge network, not from your Dev Container or Ona's port forwarding.
### Ona Tasks and Services
When running containerized services with `docker run`, use `--network host` or map ports explicitly with `-p` to make them accessible. See [containerized service examples](/docs/ona/configuration/tasks-and-services/examples#containerized-services) for recommended patterns.
## Relationship to devcontainer port properties
The `devcontainer.json` spec includes `forwardPorts` and `portsAttributes` properties. These are standard devcontainer properties that tell the editor which ports to forward from the container and how to configure them (labels, auto-forward behavior).
These properties work in Ona across VS Code-based editors, but they operate independently from Ona's port sharing. They do not create shareable URLs or open ports in the Ona dashboard.
| Mechanism | What it does | Use case |
| ---------------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------- |
| `forwardPorts` / `portsAttributes` | Editor-managed port forwarding, auto-forward notifications, port labels | Per-developer access in VS Code-based editors |
| `ona environment port open` | Ona URL with TLS and configurable access, visible in dashboard | Browser previews, webhooks, and CI integrations |
## Opening a port and previewing in the browser
Use the [built-in web browser](/docs/ona/integrations/web-browser) when you want a preview to stay inside the environment page and remain available to Ona.
You can open a port and launch the preview URL in a single command using the `$BROWSER` variable:
```bash theme={null}
$BROWSER "$(ona environment port open 8000 -n my-app)"
```
To see which ports are currently listening in your environment:
```bash theme={null}
ss -tlnp
```
## Limitations
* Ports 1024–65535 can be exposed. System ports (1–1023) are not supported.
* Not available on local environments
* Subject to fair use policies and bandwidth limits
* Organization administrators can disable port sharing via [organization policies](/docs/ona/organizations/policies/port-sharing). VS Code Browser and agents are exempt from this restriction.
Network flags like `--network=host` in `build.options` are stripped during Dev Container builds. Host network mode is only applied at runtime when the container starts.
# README button
Source: https://ona.com/docs/ona/integrations/readme-button
Add a "Build with Ona" button to your repository README for one-click environment creation.
Add a badge to your repository README so contributors can open the project in an Ona environment with one click. The badge links to `app.ona.com/#` — Ona clones the repo, applies your [Dev Container](/docs/ona/configuration/devcontainer/overview) configuration, and starts the environment automatically.

## Markdown
```markdown theme={null}
[](https://app.ona.com/#)
```
Replace `` with the full URL to your repository on any [supported SCM provider](/docs/ona/source-control/overview). For example:
```markdown theme={null}
[](https://app.ona.com/#https://github.com/gitpod-io/empty)
```
## HTML
```html theme={null}
```
See [Open from URL](/docs/ona/integrations/ona-url) for the full URL format, including pre-selecting a runner or environment class.
# Ona SDK
Source: https://ona.com/docs/ona/integrations/sdk
Create environments, run commands, and start Codex agents from Python, TypeScript, or Go.
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
**SDK versions 1.x introduce a new API that is not compatible with versions 0.x.** The package names remain the same, so update your code when upgrading from a 0.x version to a 1.x version. Follow [Migrate from SDK versions 0.x](/docs/api-reference/sdk-migration) for language-specific instructions.
Use the Ona SDK to create and manage environments, run commands, access files, and start Codex agents from Python, TypeScript, or Go.
## Install an SDK
Install the [`gitpod-sdk` package](https://pypi.org/project/gitpod-sdk/):
```bash theme={null}
python -m pip install gitpod-sdk
```
Import the high-level SDK from `ona_sdk`. Python 3.10 or later is required.
Install the [`@gitpod/sdk` package](https://www.npmjs.com/package/@gitpod/sdk):
```bash theme={null}
npm install @gitpod/sdk
```
The package supports CommonJS and ECMAScript modules on Node.js 20 and later.
Install the [`github.com/gitpod-io/gitpod-sdk-go` module](https://github.com/gitpod-io/gitpod-sdk-go):
```bash theme={null}
go get github.com/gitpod-io/gitpod-sdk-go
```
Import `github.com/gitpod-io/gitpod-sdk-go/sdk` for high-level workflows. Go 1.25 or later is required.
## Authenticate the SDK
Create a [personal access token](/docs/ona/integrations/personal-access-token), then set `ONA_API_KEY`:
```bash theme={null}
export ONA_API_KEY=""
```
The SDK reads `ONA_API_KEY` when you use `create_client_from_env`, `createClientFromEnv`, or `sdk.NewFromEnv`.
The default API URL is `https://app.ona.com/api`. If your organization uses a custom management-plane domain, also set:
```bash theme={null}
export ONA_BASE_URL="https:///api"
```
Python applications can use `create_client(api_key=..., base_url=...)`, and TypeScript applications can use `createClient({ apiKey, baseUrl })`. Do not commit tokens to source control.
## Create an environment and run a command
Each high-level client creates a running environment from a repository URL and returns an environment handle. The handle provides command, file, Git, and agent operations.
```python theme={null}
from ona_sdk import create_client_from_env
ona = create_client_from_env()
environments = ona.environments()
environment = environments.create(
"https://github.com/gitpod-io/template-golang-cli"
)
try:
result = environment.run_command(
command="pwd && git status --short",
working_directory=environment.workspace_dir(),
)
print(result.stdout)
finally:
environments.delete(environment.id(), force=True)
```
```typescript theme={null}
import { createClientFromEnv } from "@gitpod/sdk";
const ona = createClientFromEnv();
const environments = ona.environments();
const environment = await environments.create({
contextUrl: "https://github.com/gitpod-io/template-golang-cli",
});
try {
const result = await environment.runCommand({
command: "pwd && git status --short",
workingDirectory: environment.workspaceDir(),
});
console.log(result.stdout);
} finally {
await environments.delete(environment.id(), { force: true });
}
```
```go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
)
func main() {
ctx := context.Background()
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
environments := ona.Environments()
environment, err := environments.Create(ctx, sdk.CreateEnvironmentOptions{
ContextURL: "https://github.com/gitpod-io/template-golang-cli",
})
if err != nil {
log.Fatal(err)
}
defer environments.Delete(ctx, environment.ID(), sdk.DeleteEnvironmentOptions{Force: true})
status := environment.Proto().GetStatus()
workspaceDir := status.GetDevcontainer().GetRemoteWorkspaceFolder()
if workspaceDir == "" {
workspaceDir = status.GetContent().GetContentLocationInMachine()
}
result, err := environment.RunCommand(ctx, sdk.RunCommandOptions{
Command: "pwd && git status --short",
WorkingDirectory: workspaceDir,
})
if err != nil {
log.Fatal(err)
}
fmt.Print(result.Stdout)
}
```
## Choose high-level workflows or direct API clients
Use the high-level SDK for environment and Codex workflows. It handles tasks such as resolving repository context, selecting an environment class, waiting for state changes, connecting to environment operations, and mapping common failures to typed errors.
Use the generated clients when the high-level SDK does not cover an API operation:
* **Python:** protobuf messages are under `gitpod.v1`, and authenticated synchronous service clients are available from `ona.services`.
* **TypeScript:** core service clients are available from `ona.services`. Generated protobuf schemas and service descriptors are exported from subpaths such as `@gitpod/sdk/gitpod/v1/environment_pb`.
* **Go:** protobuf messages are in `github.com/gitpod-io/gitpod-sdk-go/v1`, and generated Connect clients are in `github.com/gitpod-io/gitpod-sdk-go/v1/v1connect`.
Direct API clients use protobuf request and response messages. See the [API reference](https://ona.com/docs/api-reference) for the available services, methods, and fields. The API also covers organization reporting through the [Ona Intelligence usage API](/docs/ona/billing/ona-intelligence-usage-api) and [AI cost usage API](/docs/ona/billing/cost-usage-api).
## Run the full examples
The published SDK packages include runnable examples for environment operations and Codex agents:
* [Python package files](https://pypi.org/project/gitpod-sdk/#files): download the source distribution and open `examples/`.
* [TypeScript package examples](https://unpkg.com/browse/@gitpod/sdk@latest/examples/)
* [Go module source](https://github.com/gitpod-io/gitpod-sdk-go): open `sdk/examples/`.
## Troubleshooting
Set `ONA_API_KEY` in the process that starts your application. SDK versions 1.x prefer `ONA_API_KEY`; `GITPOD_API_KEY` is supported as a compatibility fallback.
Set `ONA_BASE_URL` to your custom management-plane origin followed by `/api`, for example `https://ona.example.com/api`. Do not use the `vscode.` subdomain.
# Terraform provider
Source: https://ona.com/docs/ona/integrations/terraform-provider
Manage runners, projects, organization settings, automations, and more.
Review, version, and apply organization configuration alongside your infrastructure with the [Terraform provider](https://registry.terraform.io/providers/gitpod-io/ona/latest).
The provider is in beta. Pin an exact version, review each upgrade, and test upgrades outside production before broad rollout.
See the complete [resource reference and configuration examples](https://registry.terraform.io/providers/gitpod-io/ona/latest/docs).
## Common use cases
### Deploy and share runner infrastructure
Create a runner record and registration token, then pass the runner ID and token to the cloud module that deploys its infrastructure. This keeps control-plane and cloud resources in one dependency graph.
* Use the [AWS runner module](https://github.com/gitpod-io/terraform-aws-ona-runner) to deploy an AWS runner in your VPC.
* Use the [GCP runner module](https://registry.terraform.io/modules/gitpod-io/ona-runner/google/latest) to deploy a GCP runner in your project.
* Share the registered runner with groups as described in [Sharing resources](/docs/ona/organizations/sharing-resources).
The registration token expires after 24 hours and can be used once. Terraform marks it as sensitive but stores it in state so a cloud module can consume it. Use an encrypted, access-controlled remote state backend.
### Standardize organization settings
Manage organization-wide settings such as environment lifecycle limits, project creation rules, agent policies, security policies, identity configuration, custom domains, announcements, and terms of service.
Some resources reset, disable, or preserve remote settings when destroyed, so review the Registry documentation and the destroy plan before applying a removal.
### Manage and share automations
Define an Automation's triggers, execution context, Codex settings, limits, and steps. Grant groups the Viewer, Executor, or Admin role as described in [Sharing Automations](/docs/ona/automations/sharing-automations).
### Manage and share projects
Create projects with their repository, branch, environment classes, and prebuild configuration. Import existing projects without recreating them. Grant groups access as described in [Project sharing](/docs/ona/projects/project-sharing).
## Configure the provider
Terraform CLI 1.14 or later is required. Packages for Linux `amd64` and Linux `arm64` are available; macOS and Windows packages are not available.
Follow the [installation instructions](https://registry.terraform.io/providers/gitpod-io/ona/latest) and pin your chosen version.
Create a read-and-write [personal access token](/docs/ona/integrations/personal-access-token) and keep it outside the configuration:
```bash theme={null}
export ONA_TOKEN=""
terraform init
terraform plan
```
Use a token owned by someone who can read and change every managed object.
Service account token support varies by API. Use a personal access token for writes unless Support confirms that a service account token works for your use case.
If your organization uses a custom management-plane domain, set `ONA_HOST` to that origin:
```bash theme={null}
export ONA_HOST="https://"
```
## Protect state and review destructive changes
The `sensitive` marker redacts values in normal command output but does not exclude ordinary attributes from state. Treat state and saved plans as sensitive data. Use write-only arguments and ephemeral resources when the Registry reference lists them.
Managed resources support import. Terraform Query can discover many existing resources and generate import blocks, but not for every resource.
Removing a resource block usually plans to delete the remote object. Use `terraform state rm ` to stop managing an object without deleting it. Review the [state, secrets, and safe deletion guide](https://registry.terraform.io/providers/gitpod-io/ona/latest/docs/guides/state-secrets-and-safe-deletion) and every destroy plan before applying changes.
## Releases and support
* Review the [reference](https://registry.terraform.io/providers/gitpod-io/ona/latest) for supported resources, data sources, imports, and examples.
* Follow [releases](https://github.com/gitpod-io/terraform-provider-ona/releases) and the [changelog](https://github.com/gitpod-io/terraform-provider-ona/blob/main/CHANGELOG.md) before upgrading.
* Browse the [source repository](https://github.com/gitpod-io/terraform-provider-ona).
* Report security issues through the [security policy](https://github.com/gitpod-io/terraform-provider-ona/security/policy).
* For account access, organization setup, or product behavior, open **Support** from the organization menu in the dashboard.
# Built-in web browser
Source: https://ona.com/docs/ona/integrations/web-browser
Open the built-in browser in an environment, preview local apps, and share browser context with Ona.
Use the built-in web browser to inspect a web app from an Ona environment. When Ona AI is enabled, you can also share page state with Ona and send screenshots from the Browser tab into the conversation. The browser runs inside the environment, so it can access services on that environment's local ports.
The built-in web browser is enabled by default for all organization tiers. Enterprise admins can disable it with the [web browser organization policy](/docs/ona/organizations/policies/web-browser).
## Where the browser is available
The built-in browser appears on environment pages when all of these are true:
* The environment is in a phase where actions can be opened, such as a running environment.
* The organization allows the built-in browser.
* The environment supervisor supports the browser controller.
When available, the dashboard shows **Open Browser**, **Preview ... in Browser**, or the **Browser** tab. If the browser is not available, port previews fall back to external shared-port links.
The **Annotate browser** and **Send screenshot to Ona** actions appear only when Ona AI is enabled for the organization.
## Enable or disable the browser
The browser is enabled by default for Free, Core, and Enterprise organizations. Enterprise admins can disable or re-enable it from **Settings > Organization > Policies > Allow Web Browser in Environments**.
Disabling the policy has these effects:
* The dashboard hides browser actions and the Browser tab.
* Ona does not expose the `browse-web` built-in skill to agents in that organization.
* Members cannot start the environment's managed browser session from the dashboard.
Disabling the policy does not disable [port sharing](/docs/ona/integrations/ports), [VS Code Browser](/docs/ona/editors/vscode-browser), or editor access. Those features have separate controls.
## Security and ports
The built-in browser is separate from shared port URLs. Opening a local app in the Browser tab does not make that app public. For port previews, Ona navigates the managed browser to an environment-local address, such as `http://localhost:3000`.
Port sharing is still relevant for the browser's own connection. When the browser starts, Ona declares a managed browser port so the dashboard can connect to the browser session. That managed port is for the Browser tab and is not the same as sharing your app's port with other people.
Use [port sharing](/docs/ona/integrations/ports) when you need a URL outside Ona, such as a teammate preview link or a webhook callback URL. Use the built-in browser when you want a preview inside Ona that you and Ona can both inspect.
When you ask Ona to open the exact published URL of a protected port in the current environment, Ona authenticates that browser navigation automatically. This does not make the port public or change its admission level. Authentication is scoped to that port URL and reused within the environment's browser session until it expires.
## Open the browser manually in the product
Open the browser from an environment details page:
1. Open a running environment.
2. Select **Open Browser** to open a blank Browser tab.
3. To preview a local app, select **Preview ... in Browser** from a listed port.
If the browser is not already running, Ona starts it for the environment and opens the Browser tab.
You can also use the Browser tab directly:
* Type a URL in the browser address field.
* Use back, forward, reload, and external-open controls from the Browser tab header.
* Switch between desktop and mobile viewport mode.
* Close the Browser tab without stopping the environment.
## Ask Ona to use the browser
When Ona AI is enabled, ask Ona to use the browser when a task requires visual inspection, page interaction, screenshots, videos, console output, or network requests. Mention the URL or port and the behavior you want checked.
Examples:
* `Open the browser and verify the app on port 3000 loads without console errors.`
* `Use the browser to reproduce the login bug on localhost:8080 and tell me which step fails.`
* `Open the settings page in the browser, take a screenshot, and explain why Save is disabled.`
* `Record a short video of the onboarding flow in the browser and attach it to the conversation.`
If your app is not already running, include that in the prompt:
```text theme={null}
Start the frontend, open it in the browser on port 5173, and check whether the checkout modal still overflows on mobile.
```
The Browser tab and Ona use the same browser session for the environment. If you navigate, sign in, or change page state manually, Ona can continue from that state. If Ona navigates or fills a form, you can watch the change in the Browser tab.
## Send screenshots and annotations to Ona
When Ona AI is enabled, use screenshots when Ona needs to inspect the exact page state you are seeing.
* **Send screenshot to Ona** captures the current Browser tab and opens a message prompt with the screenshot attached.
* **Annotate browser** lets you draw on the page, describe what to change, and send the annotated screenshot to Ona.
* **Mobile viewport** switches the Browser tab between desktop and mobile viewport modes before you capture or annotate.
Use annotations for precise UI feedback, such as pointing at an overflowing element, a missing label, or a disabled button. Use a plain screenshot when the whole page state is enough.
After you send the annotation, Ona receives the marked-up screenshot in the conversation and can respond to the highlighted page state.
You can also ask Ona to capture artifacts while it uses the browser:
* `Use the browser to open the dashboard on port 3000 and attach a screenshot of the billing page.`
* `Record a short video of the signup flow in the browser and tell me where the error appears.`
* `Take screenshots before and after submitting the form so I can compare the UI states.`
## FAQ
No. Opening a port in the built-in browser keeps the preview inside the environment page. Use [Port sharing](/docs/ona/integrations/ports) when you need a URL that can be opened outside the environment page.
Yes. The Browser tab and Ona share the same browser session for the environment, so Ona can continue from the state that is already open.
No. Port sharing and the built-in browser use separate policies. The built-in browser is controlled by the [web browser policy](/docs/ona/organizations/policies/web-browser).
Yes, when Ona AI is enabled. Ona and the Browser tab use the same browser session for the environment. If you sign in, navigate, or change page state in the Browser tab, Ona can continue from that state when you ask it to use the browser.
## Troubleshooting
The environment may not be running, the environment supervisor may not support the browser yet, or your Enterprise organization may have disabled the web browser policy. Ask an organization administrator to check **Settings > Organization > Policies > Allow Web Browser in Environments**.
The environment may be running on a supervisor version that does not support the built-in browser. Restart the environment after the runner is upgraded, then try opening the browser again.
Check that the app is running and listening on the expected port. If the app also needs to be reachable through Ona port handling, follow the bind-address and network guidance in [Port sharing](/docs/ona/integrations/ports#prerequisites).
# MCP servers
Source: https://ona.com/docs/ona/mcp
Extend agents with external tools using the Model Context Protocol
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/guide/) extends agents with external tools such as GitHub, Linear, and browser automation. MCP servers run as separate processes in your environment and communicate over stdio or HTTP.
There are two ways to add MCP servers to Ona:
* **[Custom organization integrations](#custom-organization-mcp-integrations)**: Administrators add HTTP MCP servers from the dashboard so everyone in the organization can use them. OAuth is set up automatically via Dynamic Client Registration, or manually with a client ID and secret.
* **[Repo-local configuration](#repo-local-mcp-configuration)**: Developers commit `.ona/mcp-config.json` to a repository to configure servers per project. Supports both stdio and HTTP transports, and lets you inject secrets at runtime.
## Custom organization MCP integrations
Administrators can add custom MCP servers to an organization from the dashboard. Custom integrations use HTTP transport and OAuth. You can set up OAuth in one of two ways:
* **Automatic (DCR)**: Ona registers itself with the MCP server using [Dynamic Client Registration (DCR)](https://datatracker.ietf.org/doc/html/rfc7591), with no pre-shared client ID or secret. Requires the MCP server to expose a DCR endpoint.
* **Manual**: You register Ona with your OAuth provider and supply a client ID and secret. Use this when the MCP server does not support DCR.
Use custom integrations when you want to make an MCP server available to everyone in the organization without each developer configuring it locally.
### OAuth setup
Before adding an integration, decide how Ona authenticates with the MCP server. You'll choose one of these modes in the create dialog.
#### Automatic (DCR)
The default. The MCP server must support [RFC 7591 OAuth 2.0 Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591). Ona registers itself with the server automatically on first use. No further configuration is required.
#### Manual
Use this when the MCP server does not support DCR. You register Ona with the OAuth provider yourself and provide the resulting credentials:
* **Callback URL**: Copy this value and register it as the redirect URI in your OAuth provider before saving.
* **Client ID**: The client ID issued by your OAuth provider.
* **Client secret**: The client secret issued by your OAuth provider.
* **Authorization URL** (optional): The OAuth authorization endpoint. Auto-discovered from the MCP server's [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414) metadata if left blank.
* **Token URL** (optional): The OAuth token endpoint. Auto-discovered if left blank.
* **Scopes** (optional): OAuth scopes to request, separated by newlines, spaces, or commas. Auto-discovered when the authorization URL is left blank.
### Add a custom integration
1. Go to [Settings > Integrations](https://app.ona.com/settings/org-integrations)
2. Click **Add MCP Integration**
3. Enter:
* **Name**: Display name shown to members (for example, `Hex`)
* **MCP URL**: The MCP server endpoint (for example, `https://hex.tech/mcp/sse`)
* **OAuth setup**: Choose **Automatic (DCR)** or **Manual** (see [OAuth setup](#oauth-setup) above). Manual reveals additional credential fields.
* **Description** (optional): Short description shown on the integration card
4. Click **Create**
The integration is created disabled. Enable it from the integrations list when you're ready to make it available to the organization.
### Authenticate
Once enabled, each user connects their own account from [User Settings > Integrations](https://app.ona.com/?user-settings=integrations). Service accounts connect from the service account details page. Ona kicks off the OAuth flow so the agent acts with the selected user's or service account's permissions. For automatic integrations, Ona performs DCR against the MCP server on first use; for manual integrations, it uses the client credentials you provided.
## Repo-local MCP configuration
Create `.ona/mcp-config.json` in your repository:
```json theme={null}
{
"mcpServers": {
"github": {
"name": "github",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${exec:printf 'protocol=https\nhost=github.com\n' | git credential fill 2>/dev/null | awk -F= '/password/ {print $2}' 2>/dev/null}"
},
"timeout": 30,
"toolDenyList": ["search_code"]
},
"playwright": {
"name": "playwright",
"command": "npx",
"args": ["-y", "@executeautomation/playwright-mcp-server"],
"timeout": 60
}
},
"globalTimeout": 30
}
```
### Transport types
Each server uses either **stdio** or **HTTP** transport. Ona detects the transport from your config:
* Set `command` for stdio transport (runs a local process)
* Set `url` for HTTP transport (connects to a remote endpoint)
A server cannot have both `command` and `url`.
### Configuration options
| Field | Transport | Description |
| -------------- | --------- | -------------------------------------------------------------------------- |
| `name` | both | Display name for the server (defaults to the map key) |
| `command` | stdio | Executable to run the server |
| `args` | stdio | Command arguments |
| `url` | HTTP | Server endpoint (must start with `http://` or `https://`) |
| `headers` | HTTP | HTTP headers sent with requests (supports `${exec:...}` and `${file:...}`) |
| `env` | stdio | Environment variables (supports `${exec:...}` and `${file:...}`) |
| `timeout` | both | Per-server timeout in seconds (default: 30) |
| `toolDenyList` | both | Exact tool names to block |
| `workingDir` | stdio | Working directory for the server process |
| `disabled` | both | Set `true` to disable without removing config |
Set `globalTimeout` at the top level of the config to apply a default timeout to all servers.
## Checking MCP server status
Click the **MCP Integrations** button in the session input to see server status. Each server shows whether it is connected, disabled, or experiencing errors.
## Examples
### Stdio transport (local process)
[@executeautomation/playwright-mcp-server](https://www.npmjs.com/package/@executeautomation/playwright-mcp-server) runs as a local process via `npx`:
```json theme={null}
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["-y", "@executeautomation/playwright-mcp-server"],
"timeout": 60
}
}
}
```
### HTTP transport (remote server)
Connect to an MCP server running over HTTP. Use `url` instead of `command`:
```json theme={null}
{
"mcpServers": {
"my-remote-server": {
"url": "https://mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer ${exec:printenv MCP_API_TOKEN}"
},
"timeout": 60
}
}
}
```
`headers` supports `${exec:...}` and `${file:...}` expansion, like `env`. Inject tokens at runtime instead of committing secrets.
## Credentials
Use [Ona Secrets](/docs/ona/configuration/secrets/overview) to inject credentials into `env` (stdio) or `headers` (HTTP):
```json theme={null}
{
"env": {
"API_TOKEN": "${exec:printenv API_TOKEN}",
"SERVICE_KEY": "${exec:your-secrets-cli get service/key}"
}
}
```
For HTTP servers, inject tokens via `headers`:
```json theme={null}
{
"headers": {
"Authorization": "Bearer ${file:/run/secrets/api-token}"
}
}
```
* **Environment variables**: `${exec:printenv VAR_NAME}`
* **Files**: `${file:/path/to/secret}`
* **External stores**: `${exec:aws secretsmanager get-secret-value ...}`
Avoid committing secrets to source control. Provision them at runtime using [Ona Secrets](/docs/ona/configuration/secrets/overview).
## DevContainer requirements
MCP servers run inside your environment. The base image must include the tools they need (`npx` for Node-based servers, `docker` for container-based servers). If a server fails to start, verify the required runtime is in your Dev Container image.
## Applying configuration changes
Ona reads MCP configuration once at the start of each agent execution. Changes are **not picked up mid-conversation**, regardless of whether they are in `.ona/mcp-config.json`, organization integrations, or the org-level MCP toggle.
### Local config (`.ona/mcp-config.json`)
After creating or modifying the file:
1. **Save** the file in your workspace
2. Start a **new agent execution**: open a new Ona conversation, or wait for the current execution to finish and send a new message
The agent reads the file from your workspace filesystem at the start of each execution. You do not need to rebuild the Dev Container or create a new environment.
Commit the file to your repository when you're ready to share the config with new environments.
### Organization integrations (dashboard)
Changes to MCP integrations in [Settings > Integrations](https://app.ona.com/settings/org-integrations) take effect on the next agent execution. No environment changes are needed.
### Organization MCP toggle
Enabling or disabling MCP in [Settings > Agents > Policies](https://app.ona.com/settings/agent-policies) takes effect on the next agent execution.
## Organization controls
Organization owners can disable MCP in [Settings > Agents > Policies](https://app.ona.com/settings/agent-policies). When disabled:
* `.ona/mcp-config.json` files are ignored
* Agent operates with built-in tools only
* External MCP connections are blocked
See [Audit logs](/docs/ona/audit-logs/overview) to review changes.
## Troubleshooting
The agent may not list MCP tools when asked, but can still invoke them. Type `/support-bundle` in your Ona session to verify servers are connecting.
If your MCP configuration has syntax errors or invalid server definitions, the agent logs the error and skips the misconfigured server. Check the MCP Integrations panel in the conversation input for error details.
# Home notice
Source: https://ona.com/docs/ona/organizations/announcement-banner
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Home notices let organization admins communicate important information to all members. Notices appear on the Ona home page and remain visible until disabled.
## Configure the notice
1. Go to **Settings → Organization → Announcements**
2. Turn on **Show announcement**
3. Enter your message (up to 1,000 characters)
4. Click **Save**
The notice appears immediately on the home page for all organization members.
## Formatting
Home notices support basic Markdown for emphasis and links. A live preview shows exactly how your message will appear.
| Syntax | Result |
| ------------------------ | -------------- |
| `**bold**` | **bold** |
| `*italic*` or `_italic_` | *italic* |
| `[link text](url)` | Clickable link |
## Use cases
* Scheduled maintenance windows
* New feature announcements
* Policy changes or reminders
* Security notices
* Team-wide updates
## Disable the notice
Toggle off **Show announcement** in the settings. Your message is preserved and can be re-enabled later.
## FAQ
All organization members see the notice when logged in. It appears on the Ona home page.
Yes. When you enter a message, a live preview appears below the text field showing exactly how it will look.
Only organization administrators can access the Announcements settings page.
# Create or join an organization
Source: https://ona.com/docs/ona/organizations/create-organization
When signing in for the first time, Ona prompts you to create a new organization. You'll automatically be the admin.
Organizations are the top-level boundary for people, projects, runners, policies, and secrets. Most teams have one organization per company or engineering group, though you can belong to more than one.
## Create an organization
1. Enter an organization name (can be changed later in Settings)
2. Optionally enable "Anyone with a *yourdomain.org* domain can join" to allow users with matching email domains to join automatically
## Join an organization
If organizations exist that allow you to join (via domain matching), you'll see them listed. Click **Join** to become a member.
### From an invite link
Clicking an invite link takes you directly to the join page for that organization.
### From the menu
You can access the join/create dialog anytime from the account dropdown menu.
## Create vs join
* **Create** when you are setting up a new team space and need admin control over projects, runners, policies, and members.
* **Join** when your team already has an organization and you only need access to shared resources inside it.
## What happens next
After creating or joining an organization, the usual next steps are:
* invite or manage members
* create or connect projects
* add runners or use Ona Cloud
* configure login, policies, and secrets for the team
See [Manage organization](/docs/ona/organizations/manage-organization) and [Team management](/docs/ona/organizations/overview) for the next layer of setup.
# Insights
Source: https://ona.com/docs/ona/organizations/insights
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Insights gives organization admins and Insights Viewers visibility into how their teams ship code, adopt AI tooling, and use environments. Access it from **Insights** in the left navigation menu.
The page is organized into three sections:
* **Velocity.** How fast your organization ships code.
* **AI Adoption.** How your organization leverages AI to ship code.
* **Platform usage.** How your organization uses Ona environments.
## Enabling insights
Velocity and AI Adoption require per-project enablement. Platform usage data is collected automatically for all projects.
To enable insights for a project:
1. Go to **Insights** and click **Manage** in the page header.
2. Toggle on the projects you want to track.
You can also enable insights from a project's settings page under the **Insights** toggle.
When you enable insights for a project, a daily automation runs on behalf of your organization to analyze development activity. This incurs a small amount of usage costs.
After enabling, the first analysis is triggered automatically. Initial results may take up to 24 hours to appear depending on repository size and history. Subsequent analyses run automatically.
The page header shows how many of your projects have insights enabled (e.g. "3 of 12 projects have insights enabled") and when the last analysis ran.
## Filters
All three sections share a set of filters at the top of the page:
* **Date range.** Pick a preset (Last 7 days, Last 14 days, Last 30 days, Last 90 days, Last 6 months, Last year) or enter a custom range. The maximum range is one year.
* **Project.** Scope all metrics to a single project, or view across all projects.
* **Team.** Scope all metrics to a specific team.
Charts support brush-zoom: click and drag on any chart to zoom into a narrower date range.
Each section also has an **Aggregate by** toggle to switch between daily and weekly granularity.
## Summary cards
At the top of the page, three summary cards provide an at-a-glance overview:
| Card | Hero metric | Additional stats |
| ------------------ | ----------------------- | ------------------------------------------------ |
| **Velocity** | Lead time | PRs merged, Time to first approval, Deploys/week |
| **AI Adoption** | AI-assisted commits (%) | AI commits, Agent exec/user, Agent sessions |
| **Platform usage** | Env hrs/user | Active users, Power users, Environment sessions |
Each card includes a sparkline and trend indicator comparing the selected period to the previous period of equal length. Click a card to scroll to its section.
## Velocity
Tracks PR shipping speed across all projects with insights enabled.
| Metric | Definition |
| -------------------------- | ------------------------------------------------------------------------------------------------------------ |
| **Lead time** | Median time from first commit on a branch to PR merge |
| **PRs merged** | Total pull requests merged across all projects in scope |
| **Time to first approval** | Median time from PR opened to first approving review |
| **Deploys/week** | PRs merged to each project's configured branch, per week. Projects without a configured branch are excluded. |
Click a metric card to view its time-series chart. Use the **Aggregate by** toggle to switch between daily and weekly buckets.
For lead time and time to first approval, a downward trend is positive (faster shipping). For PRs merged and deploys/week, an upward trend is positive.
## AI Adoption
Shows how your organization leverages AI agents in development. Uses commit co-author trailers and AI authorship metadata to attribute changes to tools like Ona, Copilot, Cursor, Codex, and Claude.
### Metric cards
| Metric | Definition |
| ----------------- | ------------------------------------ |
| **Commits** | Total commits in the selected period |
| **Lines added** | Total lines added |
| **Lines removed** | Total lines removed |
| **Authors** | Distinct commit authors |
Click a metric card to view its time-series chart.
### Breakdown modes
For the **Lines added** and **Lines removed** views, a toggle switches between two attribution methods:
* **By co-author.** Attributes lines based on `Co-authored-by` git trailers. Breaks down into: Ona, Codex, Claude, GitHub Copilot, Cursor, Other AI, Other Co-author, and Human only.
* **By agent output.** Attributes lines based on AI authorship metadata tracked at the session level.
Each breakdown includes a table below the chart showing per-tool totals and percentages.
## Platform usage
Tracks how your organization uses Ona environments across all projects. This data is collected automatically and does not require per-project enablement.
### Metric cards
| Metric | Definition |
| ---------------- | --------------------------------------------------------------------- |
| **Active users** | Unique users who used at least one environment in the selected period |
| **Environments** | Number of environments that were active in the selected period |
| **Total time** | Accumulated environment runtime hours |
Click a metric card to view its time-series chart.
### Detailed views
Below the chart, three tables show:
| Table | Shows |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| **Most active users** | Users ranked by total runtime hours |
| **Top projects** | Projects ranked by total environment usage time |
| **Top environment classes** | Resource consumption by class (e.g. Large, Regular). Local runners are aggregated for comparison with remote runners. |
## API access
Query all Insights data programmatically with the [Insights API](/docs/ona/organizations/insights-api) for BI tooling, scheduled reports, or tracking AI adoption across teams.
## FAQ
Organization admins can view and manage Insights. Members with the Insights Viewer organization role can view Insights, but cannot enable project insights.
No. The daily analysis runs in a separate environment and does not interfere with developer workflows.
Ona, Codex, Claude, GitHub Copilot, and Cursor. Other AI co-authors are grouped under "Other AI". Human co-authors (pair programming) are shown separately.
A PR merged to the project's configured branch. If a project does not have a configured branch, it is excluded from the deploys metric.
Yes, platform usage data persists after environments are deleted.
Platform usage data is available from May 16, 2025 onwards regardless of when you enabled insights. Velocity and AI Adoption data starts from when you enable insights for each project.
# Insights API
Source: https://ona.com/docs/ona/organizations/insights-api
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
The Insights API exposes the data behind the [Insights dashboard](/docs/ona/organizations/insights): adoption and usage, AI co-authored commits, agent sessions, and PR speed. Use it to feed BI tools, build internal reports, or track AI adoption across teams.
For metric definitions and how to enable insights for projects, see [Insights](/docs/ona/organizations/insights). Velocity and AI adoption endpoints return data only for projects with insights enabled.
## Authentication
All endpoints accept a Bearer token: a [personal access token](/docs/ona/integrations/personal-access-token) (acts as you) or a [service account token](/docs/ona/organizations/service-accounts) (owned by the organization, recommended for ongoing automation).
```bash theme={null}
export GITPOD_API_KEY="your-token"
```
## Request format
Every endpoint is a POST with a JSON body:
```text theme={null}
POST https://app.gitpod.io/api/gitpod.v1.UsageService/
```
| Parameter | Required | Description |
| ------------ | ---------------- | --------------------------------------------------------------------------------------------------- |
| `dateRange` | Yes | `startTime` and `endTime` as RFC-3339 timestamps. Maximum range is one year. |
| `projectId` | No | Scope results to a single project. Requires read access to that project. |
| `userId` | No | Scope results to a single user. Mutually exclusive with `teamId`. |
| `teamId` | No | Scope results to members of a [team](/docs/ona/organizations/teams). Mutually exclusive with `userId`. |
| `resolution` | Time series only | Bucket size: `RESOLUTION_HOURLY`, `RESOLUTION_DAILY`, `RESOLUTION_WEEKLY`, or `RESOLUTION_MONTHLY`. |
Responses follow two conventions:
* All `*Trend` fields are the fractional change against the previous period of equal length, computed as `(current - previous) / previous`. For example, `0.25` means up 25% and `-0.1` means down 10%.
* 64-bit integer fields (counts, line totals) are returned as JSON strings, per protobuf JSON encoding. Parse them as integers.
## Adoption and usage summary
Returns active users, power users, environment sessions, and average environment runtime per user, each with a trend, plus a sparkline.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.UsageService/GetAdoptionUsageSummary`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.UsageService/GetAdoptionUsageSummary \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{"dateRange": {"startTime": "2026-06-09T00:00:00Z", "endTime": "2026-07-09T00:00:00Z"}}'
```
**Response:**
```json theme={null}
{
"envRuntimePerUserSeconds": 431970.5,
"envRuntimePerUserTrend": 0.12,
"activeUsersCount": "48",
"activeUsersTrend": 0.06,
"powerUsersCount": "21",
"powerUsersTrend": 0.1,
"powerUsersThresholdSeconds": "308571",
"sessionsCount": "12480",
"sessionsTrend": -0.04,
"sparkline": [
{ "time": "2026-06-09T00:00:00Z", "value": 44 },
{ "time": "2026-06-12T00:00:00Z", "value": 47 },
{ "time": "2026-06-15T00:00:00Z", "value": 51 }
]
}
```
## AI co-authored commits summary
Returns commit totals, line changes, and distinct authors, broken down per AI tool. Attribution uses `Co-authored-by` git trailers; see [AI Adoption](/docs/ona/organizations/insights#ai-adoption) for the detection rules.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.UsageService/GetCoAuthorSummary`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.UsageService/GetCoAuthorSummary \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{"dateRange": {"startTime": "2026-06-09T00:00:00Z", "endTime": "2026-07-09T00:00:00Z"}}'
```
**Response:**
```json theme={null}
{
"summary": {
"totalCommits": "412",
"totalLinesAdded": "30480",
"totalLinesRemoved": "9860",
"distinctAuthors": "24",
"byTool": [
{ "tool": "CO_AUTHOR_TOOL_NO_COAUTHOR", "commits": "118", "linesAdded": "4120", "linesRemoved": "1240", "distinctAuthors": "18" },
{ "tool": "CO_AUTHOR_TOOL_ONA", "commits": "232", "linesAdded": "21260", "linesRemoved": "7140", "distinctAuthors": "16" },
{ "tool": "CO_AUTHOR_TOOL_CLAUDE", "commits": "62", "linesAdded": "5100", "linesRemoved": "1480", "distinctAuthors": "9" }
],
"totalCommitsTrend": 0.18,
"totalLinesAddedTrend": 0.22,
"totalLinesRemovedTrend": 0.09,
"distinctAuthorsTrend": 0.04
},
"sparkline": [
{ "time": "2026-06-09T00:00:00Z", "value": 96 },
{ "time": "2026-06-16T00:00:00Z", "value": 104 }
]
}
```
`tool` is one of `CO_AUTHOR_TOOL_NO_COAUTHOR`, `CO_AUTHOR_TOOL_HUMAN_COAUTHOR`, `CO_AUTHOR_TOOL_ONA`, `CO_AUTHOR_TOOL_GITHUB_COPILOT`, `CO_AUTHOR_TOOL_CURSOR`, `CO_AUTHOR_TOOL_CLAUDE`, `CO_AUTHOR_TOOL_CODEX`, or `CO_AUTHOR_TOOL_OTHER`.
## AI co-authored commits time series
Returns the same contribution stats bucketed over time, including the AI-assisted share of lines added per bucket.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.UsageService/GetCoAuthorTimeSeries`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.UsageService/GetCoAuthorTimeSeries \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"dateRange": {"startTime": "2026-06-09T00:00:00Z", "endTime": "2026-07-09T00:00:00Z"},
"resolution": "RESOLUTION_WEEKLY"
}'
```
**Response:**
```json theme={null}
{
"timeSeries": [
{
"startTime": "2026-06-08T00:00:00Z",
"byTool": [
{ "tool": "CO_AUTHOR_TOOL_NO_COAUTHOR", "commits": "31", "linesAdded": "1080", "linesRemoved": "320", "distinctAuthors": "12" },
{ "tool": "CO_AUTHOR_TOOL_ONA", "commits": "58", "linesAdded": "5410", "linesRemoved": "1830", "distinctAuthors": "14" }
],
"totalLinesAdded": "6490",
"totalLinesRemoved": "2150",
"aiRatio": 0.83,
"totalCommits": "89",
"distinctAuthors": "16"
},
{
"startTime": "2026-06-15T00:00:00Z",
"byTool": [
{ "tool": "CO_AUTHOR_TOOL_ONA", "commits": "64", "linesAdded": "6220", "linesRemoved": "2040", "distinctAuthors": "15" }
],
"totalLinesAdded": "6220",
"totalLinesRemoved": "2040",
"aiRatio": 1,
"totalCommits": "64",
"distinctAuthors": "15"
}
]
}
```
## Agent sessions summary
Returns agent session counts and line changes, with a per-model breakdown.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.UsageService/GetAgentTraceSummary`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.UsageService/GetAgentTraceSummary \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{"dateRange": {"startTime": "2026-06-09T00:00:00Z", "endTime": "2026-07-09T00:00:00Z"}}'
```
**Response:**
```json theme={null}
{
"summary": {
"totalSessions": "1240",
"totalLinesAdded": "382400",
"totalLinesRemoved": "76110",
"byModel": [
{ "model": "SUPPORTED_MODEL_OPUS_4_8", "sessions": "820", "linesAdded": "268900", "linesRemoved": "51200" },
{ "model": "SUPPORTED_MODEL_SONNET_5", "sessions": "420", "linesAdded": "113500", "linesRemoved": "24910" }
],
"totalSessionsTrend": 0.31,
"totalLinesAddedTrend": 0.27,
"totalLinesRemovedTrend": 0.19
},
"sparkline": [
{ "time": "2026-06-09T00:00:00Z", "value": 274 },
{ "time": "2026-06-16T00:00:00Z", "value": 301 }
]
}
```
## Agent sessions time series
Returns agent sessions and line changes bucketed over time.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.UsageService/GetAgentTraceTimeSeries`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.UsageService/GetAgentTraceTimeSeries \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"dateRange": {"startTime": "2026-06-09T00:00:00Z", "endTime": "2026-07-09T00:00:00Z"},
"resolution": "RESOLUTION_WEEKLY"
}'
```
**Response:**
```json theme={null}
{
"timeSeries": [
{
"startTime": "2026-06-08T00:00:00Z",
"totalSessions": "274",
"totalLinesAdded": "84300",
"totalLinesRemoved": "16750",
"byModel": [
{ "model": "SUPPORTED_MODEL_OPUS_4_8", "sessions": "181", "linesAdded": "59400", "linesRemoved": "11300" },
{ "model": "SUPPORTED_MODEL_SONNET_5", "sessions": "93", "linesAdded": "24900", "linesRemoved": "5450" }
]
}
]
}
```
## PR speed summary
Returns median lead time (first commit to merge), PRs merged, median time to first approval, and deployment frequency (PRs merged to the project's configured branch, per week).
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.UsageService/GetPrSummary`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.UsageService/GetPrSummary \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{"dateRange": {"startTime": "2026-06-09T00:00:00Z", "endTime": "2026-07-09T00:00:00Z"}}'
```
**Response:**
```json theme={null}
{
"summary": {
"leadTimeSeconds": 8131.5,
"leadTimeTrend": -0.14,
"prsMergedCount": "648",
"prsMergedTrend": 0.08,
"timeToFirstApprovalSeconds": 821,
"timeToFirstApprovalTrend": -0.05,
"deploymentFrequency": 149.3,
"deploymentFrequencyTrend": 0.11
},
"sparkline": [
{ "time": "2026-06-09T00:00:00Z", "value": 148 },
{ "time": "2026-06-16T00:00:00Z", "value": 162 }
]
}
```
`timeToFirstApprovalSeconds` is zero when no PRs in the range had approvals. For lead time and time to first approval, a negative trend means faster shipping.
## PR speed time series
Returns the same PR metrics bucketed over time.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.UsageService/GetPrTimeSeries`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.UsageService/GetPrTimeSeries \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"dateRange": {"startTime": "2026-06-09T00:00:00Z", "endTime": "2026-07-09T00:00:00Z"},
"resolution": "RESOLUTION_WEEKLY"
}'
```
**Response:**
```json theme={null}
{
"timeSeries": [
{
"startTime": "2026-06-09T00:00:00Z",
"leadTimeSeconds": 6428,
"prsMergedCount": "320",
"timeToFirstApprovalSeconds": 958,
"deploys": "313"
},
{
"startTime": "2026-06-16T00:00:00Z",
"leadTimeSeconds": 10894,
"prsMergedCount": "147",
"timeToFirstApprovalSeconds": 803,
"deploys": "146"
}
]
}
```
## Combining filters
Scope any endpoint with the shared parameters. For example, a single team's weekly co-author trend:
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.UsageService/GetCoAuthorTimeSeries \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"dateRange": {"startTime": "2026-06-09T00:00:00Z", "endTime": "2026-07-09T00:00:00Z"},
"teamId": "",
"resolution": "RESOLUTION_WEEKLY"
}'
```
# Manage members
Source: https://ona.com/docs/ona/organizations/manage-members
Organization admins can manage members in **Settings → Members**: change roles, remove members, invite teammates, and view any user's environments.
## Member roles
Every user in an organization has one of these roles:
| Role | Description |
| ---------- | -------------------------------------------------------------------------------------- |
| **Admin** | Full control: manage members, create runners, configure policies, view all resources |
| **Member** | Use shared runners and projects; cannot create runners or manage organization settings |
For delegated administration without full admin access, assign [organization roles](/docs/ona/organizations/organization-roles) to groups. This lets you give specific teams management capabilities over runners, projects, groups, or automations.
## Permissions
| Permission | Admin | Member |
| ------------------------------------- | --------------------- | --------------------- |
| **Organization** | | |
| Invite members | | |
| Manage member roles | | |
| View all members | | |
| Configure policies | | |
| View audit logs | | |
| Configure SSO | | |
| **Projects** | | |
| Create projects | | Depends on policy |
| Share projects (as org admin) | | |
| Share own projects (as project admin) | | |
| Use existing projects | | |
| **Runners** | | |
| Create runners | | |
| Use runners | | When shared |
| **Environments** | | |
| Create from any repository | | Depends on policy |
| View all environments | | |
| **Secrets** | | |
| Manage project secrets | | |
| Manage personal secrets | | |
## Change a member's role
1. Click the three-dot menu next to the member's name
2. Select **Change Role**
3. Choose the new role and confirm
## Invite members
Click **Invite** at the top of the members list. There are three ways to add members:
* **Invite link**: copy the link and share it with your team. Anyone with the link can join. Click **Reset Invite Link** to invalidate existing links.
* **Invite by email**: enter email addresses to send invitations directly.
* **Allowed email domains**: allow anyone with a matching email domain to join automatically.
# Manage organization
Source: https://ona.com/docs/ona/organizations/manage-organization
Organization admins can modify settings in **Organization Settings → General**.
## Display name
Change your organization's name at any time. This affects how it appears in the UI and invite links. The name must be at least 3 characters.
## Tier
The General page shows your organization's current tier (Core or Enterprise). Click **Compare tiers** to see what each tier includes.
Core tier organizations can manage their subscription and OCUs under **Billing** in the sidebar.
## Organization ID
A read-only, copyable UUID that identifies your organization. Use this when contacting support or integrating with the Ona API.
## Delete organization
At the bottom of the page, you can permanently delete the organization. This permanently removes the organization and everything within it, including members, resources, and integrations. If the organization has a GitHub App installation connected through Ona, deleting the organization also uninstalls the GitHub App from GitHub. This action cannot be undone.
Review projects, runners, secrets, and billing implications before deleting an organization.
## Related
* [Create or join an organization](/docs/ona/organizations/create-organization)
* [Team management](/docs/ona/organizations/overview)
* [Manage members](/docs/ona/organizations/manage-members)
# Organization secrets
Source: https://ona.com/docs/ona/organizations/organization-secrets
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Organization secrets provide company-wide defaults. Shared credentials, API keys, and configuration are available to everyone in your organization. They are ideal for shared service accounts and company-wide integrations.
**Organization secrets have the lowest precedence.** Project secrets and user secrets with the same name will override them, allowing teams and individuals to customize as needed.
## Manage organization secrets
Navigate to **Settings → Organization → Secrets**.
From here you can create, edit, and delete secrets. Each secret can be an [environment variable](/docs/ona/configuration/secrets/environment-variables), [file](/docs/ona/configuration/secrets/files), or [container registry credential](/docs/ona/configuration/secrets/container-registry-secret).
## When to use organization secrets
* **Company-wide service accounts**: Shared database credentials, monitoring API keys
* **Default configuration**: Standard environment variables everyone needs
* **Container registry access**: Private images used across multiple projects
For project-specific credentials, use [project secrets](/docs/ona/projects/project-secrets). For personal credentials, use [user secrets](/docs/ona/configuration/secrets/user-secrets).
## Precedence example
If `API_KEY` exists at all three levels:
1. User secret value is used (highest)
2. Falls back to project secret
3. Falls back to organization secret (lowest)
This lets you set organization defaults while allowing projects and users to override when needed.
# Team management
Source: https://ona.com/docs/ona/organizations/overview
Organizations let teams share runners, projects, and secrets with role-based access control.
Organizations provide a shared space for development resources. Administrators can manage projects, environments, runners, and member access. For personal use, you can create an organization for yourself.
Think of an organization as the administrative and security boundary for Ona. Projects, runners, secrets, login settings, and policies all live inside an organization.
## What organizations contain
| Resource | Description |
| ----------------------------------------------------------- | --------------------------------------------------------------------------- |
| [Projects](/docs/ona/projects/overview) | Environment configurations linked to repositories |
| [Runners](/docs/ona/runners/overview) | Infrastructure for running environments |
| [Members](/docs/ona/organizations/manage-members) | Users with role-based permissions |
| [Groups](/docs/ona/organizations/groups) | Collections of members for access management |
| [Teams](/docs/ona/organizations/teams) | Organizational units used for usage attribution and per-team credit budgets |
| [Organization roles](/docs/ona/organizations/organization-roles) | Delegated admin roles for runners, projects, groups, and automations |
| [Secrets](/docs/ona/configuration/secrets/overview) | Shared credentials and API keys |
| [Policies](/docs/ona/organizations/policies/overview) | Organization-wide settings and restrictions |
## Groups vs. teams
[Groups](/docs/ona/organizations/groups) and [teams](/docs/ona/organizations/teams) are two ways to organize people in an organization. They solve different problems and most organizations use both.
* **Use a group** to answer *"who can use this runner?"* or *"who can edit this project?"*
* **Use a team** to answer *"who's on the Backend team?"* and *"how much did Backend spend this month?"*
| | **Groups** | **Teams** |
| -------------------------------- | -------------------------------------------------------------- | --------------------------------------------------------- |
| **Purpose** | Access control for projects, runners, and automations | Organizational reporting and cost management |
| **Membership** | A member can belong to **many groups** | A member belongs to **at most one team** per organization |
| **Provisioning** | Managed in Ona, or synced from your identity provider via SCIM | Managed in Ona |
| **Visibility** | Group membership is visible to organization members | All organization members can see all teams |
| **Affects billing reporting?** | No | Yes, usage is rolled up per team |
| **Affects access to resources?** | Yes | No |
See [Manage groups](/docs/ona/organizations/groups) and [Manage teams](/docs/ona/organizations/teams) for the details.
## Isolation
Organizations are hard boundaries. Resources cannot be shared or transferred between them. Each runner, project, and environment belongs to exactly one organization.
Users can be members of multiple organizations but must switch between them explicitly.
## What admins usually manage
Organization admins usually own:
* who can join and how they authenticate
* which runners and projects are available
* how resources are shared across teams
* which guardrails and policies apply by default
* what secrets and service accounts shared workflows can use
## Common operating model
For many teams, the pattern looks like this:
1. create or join the organization
2. connect identity and invite members
3. add runners or enable Ona Cloud regions
4. create shared projects
5. apply policies, secrets, and guardrails as the team grows
## Next steps
* [Create an organization](/docs/ona/organizations/create-organization)
* [Manage organization](/docs/ona/organizations/manage-organization)
* [Manage members](/docs/ona/organizations/manage-members)
* [Configure policies](/docs/ona/organizations/policies/overview)
* [Sharing resources](/docs/ona/organizations/sharing-resources)
# Sharing resources
Source: https://ona.com/docs/ona/organizations/sharing-resources
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Share projects and runners with individual users, groups, or everyone in your organization. Resource admins can manage sharing for their resources. See [Manage groups](/docs/ona/organizations/groups) for group setup.
## Share a project
Project admins can share their projects with other users and groups. When you create a project, you automatically become its admin.
1. Open the project and click **Share**
2. Click **Add users or groups**
3. Select individual users or groups to add
4. Choose a permission level for each:
| Role | Capabilities |
| ---------- | -------------------------------------------------------------- |
| **User** | View and use the project |
| **Editor** | Modify settings, manage secrets, configure environment classes |
| **Admin** | Full control including sharing and deletion |
### Change permissions
1. In the Share dialog, find the user or group
2. Click the role dropdown
3. Select a new permission level (takes effect immediately)
### Remove access
1. Click the role dropdown next to the user or group
2. Select **Remove access**
### Organization-wide access
To share with everyone in your organization:
1. In **General access**, select your organization name
2. All members get User access; you can still grant elevated permissions to specific users or groups
To restrict to specific users and groups only:
1. In **General access**, select **Only people with access**
## Share a runner
Runner admins can share their runners with other users and groups.
1. Go to **Settings → Runners**
2. Click **⋯** → **Share runner**
3. Add users or groups and assign roles (same dialog as projects)
Runner roles:
| Role | Capabilities |
| --------- | ---------------------------------------------- |
| **User** | Create environments on this runner |
| **Admin** | Configure runner settings, manage integrations |
## Access dependencies
Users need access to **both** a project and at least one of its runners to create environments.
Projects use runners through environment classes. If a user has project access but no access to any of its runners, they can see the project but cannot create environments.
### Share dialog warnings
The Share dialog displays warnings to prevent access issues:
**When sharing a project:**
> "These users will not be able to use the project unless the underlying runner is also shared with them."
**When restricting runner access:**
> "Removing access to this runner may prevent these users from using projects that depend on it."
# Terms of Service
Source: https://ona.com/docs/ona/organizations/terms-of-service
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Require members to read and accept your organization's terms of service before they can continue using Ona. Acceptance is tracked per member, per version, and per organization, and can be exported as CSV for compliance reporting.
## Enable terms of service
1. Go to **Settings → Organization → Terms of Service**
2. Write or paste your terms in the **Terms markdown** field. The editor supports up to 32,000 characters and renders a live preview alongside.
3. Toggle **Require terms acceptance** on
4. Click **Save**
The first save publishes version 1. From that moment on, members are prompted to accept the current version on their next dashboard load.
## Markdown editor
The editor accepts [GitHub Flavored Markdown](https://github.github.com/gfm/). The following are rendered:
* Headings (`#`, `##`, `###`)
* Paragraphs and line breaks
* Bold and italic emphasis
* Ordered and unordered lists
* Links: `http(s)://` and `mailto:` only; other schemes are dropped
* Inline `code` and fenced code blocks
* Blockquotes
* Tables (GFM)
The following are **not** supported:
* Images: `` tags and `` syntax are stripped
* Raw HTML: escaped as text rather than rendered
* JavaScript or other URL schemes in links: dropped silently
A live preview to the right of the editor shows exactly what members will see.
## Publish a new version
Each saved change to the markdown publishes a new immutable version. Toggling the switch on or off does not create a new version on its own.
* Versions are numbered sequentially starting at 1.
* Saving the page without changing the markdown does **not** create a new version.
* Saving the page with changed markdown creates a new version and sets it as the current version.
* Existing versions are immutable. Earlier text remains available in the acceptance report's version filter so you can reconstruct who accepted what.
When the current version changes, members who had already accepted the previous version are automatically marked as needing to re-accept on their next dashboard load. There is no separate "force re-acceptance" action; re-acceptance follows version changes.
## What members see when terms are enabled
On their next dashboard load, every active member of the organization sees:
1. A persistent banner at the top of the dashboard: *"Your organization requires you to accept its Terms of Service."* with a **Review terms** action.
2. A modal that opens automatically with the current version of the terms. The modal cannot be dismissed by clicking outside, pressing Escape, or navigating away.
3. The **Accept terms** button stays disabled until the member scrolls to the bottom of the terms. A hint reads *"Scroll to the bottom of the terms to enable Accept."* until they reach it.
The banner remains visible across the dashboard until the member reviews and accepts the current version.
Acceptance is recorded per organization and per version. A member who belongs to two organizations accepts each organization's terms independently. When the current version changes, the modal reappears with the new text.
## Acceptance reporting
Track who has accepted in **Settings → Organization → Members → Terms Acceptance**. The tab is visible to organization admins once a version has been published.
The report lists organization members matching the selected filters with their acceptance status for the selected version.
You can:
* **Filter by version**: switch between the current version and any earlier published version.
* **Filter by member status**: All, Active, or Suspended.
* **Search** by name or email.
### Export to CSV
Use the **Export CSV** button at the top of the Terms Acceptance tab to download the report. The export reflects the version, member-status filter, and search currently selected in the tab. The download arrives as a gzipped CSV named `terms-of-service-acceptances--v.csv`.
#### CSV columns
| Column | Description |
| ------------------ | --------------------------------------------------------------------- |
| `user_id` | UUID of the user. |
| `full_name` | Display name of the user. |
| `email` | Email address of the user. |
| `role` | `admin` or `member`. |
| `member_status` | Organization membership status. One of `active`, `suspended`, `left`. |
| `terms_status` | `ACCEPTED` or `PENDING`. |
| `accepted_version` | Version number the user accepted. Blank if `terms_status` is pending. |
| `accepted_at` | RFC3339 timestamp of acceptance. Blank if `terms_status` is pending. |
## Disable terms of service
Toggle **Require terms acceptance** off and click **Save**. The published versions are preserved and the acceptance history remains queryable in the Terms Acceptance tab. Re-enabling later resumes prompting members to accept the current version.
## FAQ
Only organization administrators can access the Terms of Service settings page and the Terms Acceptance tab.
Only when the markdown changes. Saving with no changes (for example, toggling the switch on and off) does not publish a new version and does not require re-acceptance.
Members who haven't accepted see the banner and the modal on their next dashboard load. They can browse to the modal and accept at any time. Acceptance is required to dismiss the modal.
No. Images are stripped and raw HTML is escaped as text. Use Markdown headings, lists, links, tables, and code blocks to structure the content.
Yes. The CSV reflects the version selector, member-status filter, and search query that are active in the Terms Acceptance tab when you click **Export CSV**.
# Project configuration
Source: https://ona.com/docs/ona/projects/overview
Projects connect a repository to runners with predefined configuration. Team members create environments from a project with one click and get the same setup every time.
## Prerequisites
* At least one runner in your organization
* By default, all organization members can create projects
* On the Enterprise tier, admins can restrict project creation to admins only via **Settings → Policies → Project policies → "Only admins can create projects"**
## Create a project
When you create a project, you become its admin. You can manage settings and share the project with other users and groups.
1. Go to your organization dashboard and navigate to the Projects page
2. Click **New Project**
3. Search for or browse to your repository
4. Enter a project name
5. Select at least one environment class
## Configuration options
| Option | Description |
| ------------------------------------------ | ------------------------------------------------------------------------------ |
| **Context URL** / **Repository Clone URL** | Repository cloned when creating environments |
| **Repository branch** | Default branch checked out (e.g., `main`, `develop`) |
| **Environment classes** | Compute resources (CPU, memory, storage) and region. Min 1, max 30 per project |
| **Dev Container path** | Path to devcontainer configuration file |
| **Tasks and services configuration path** | Optional custom path to the tasks and services configuration file |
| **Recommended editors** | Editors and versions suggested for this project |
### Environment classes
An **environment class** is a named compute configuration provided by a [runner](/docs/ona/runners/overview). Each class defines the CPU, memory, storage, and region used to run an environment, and is the unit of resource selection inside Ona. When someone starts an environment for a project, they pick from the project's allowed classes.
Each runner publishes its own set of classes (typically `Small`, `Regular`, `Large`, and sometimes specialized variants like GPU-enabled classes). The classes you select on a project determine which of those configurations are available to users creating environments for that project.
### Dev Container configuration
Controls the development environment setup: base image, VS Code extensions, environment variables, and port forwarding rules.
See [Dev Container configuration](/docs/ona/configuration/devcontainer/overview) for details.
### Tasks and services
Define automations beyond Dev Container setup:
* **Services**: long-running processes (databases, servers)
* **Tasks**: one-off actions (test runs, builds)
See [Tasks and services](/docs/ona/configuration/tasks-and-services/overview) for details.
### Recommended editors
Set which editors and versions appear as suggestions when team members open an environment.
See [Recommended editors](/docs/ona/projects/recommended-editors) for the full list of editor aliases and version configuration.
## Manage projects
Select a project from your organization dashboard to open its detail page. The detail page has tabs for **Settings**, **Secrets**, and **Prebuilds**. From **Settings** you can modify environment classes, Dev Container and tasks/services paths, recommended editors, and [project secrets](/docs/ona/projects/project-secrets).
## Limitations
Multi-repo configurations are not built-in. See [Working with multiple repositories](/docs/ona/configuration/multi-repository) for a workaround.
## Next steps
* [Create an environment](/docs/ona/environments/overview) from your project
* [Share the project](/docs/ona/organizations/sharing-resources) with your team
* [Add project secrets](/docs/ona/projects/project-secrets)
# Prebuilds
Source: https://ona.com/docs/ona/projects/prebuilds
Prebuilds reduce environment startup times by pre-executing Dev Container lifecycle commands and tasks. Instead of installing dependencies and running build steps every time, prebuilds prepare a snapshot that is ready to use.
A prebuild creates an environment, runs your Dev Container build process, lifecycle hooks (`onCreateCommand` and `updateContentCommand`), and tasks with the `prebuild` trigger. Once these commands complete, Ona snapshots the Dev Container filesystem. New environments start from this snapshot, skipping the setup steps.
## Using prebuilds
When you create an environment, Ona uses a prebuild if one is available. Selection is best-effort:
* Matches your environment class (CPU, memory, storage)
* Uses the most recent successful prebuild
* Prebuilds expire after 7 days
If no matching prebuild exists, the environment starts normally without one.
### What gets executed
During prebuild creation, Ona runs:
* **Dev Container build**: Builds your Dev Container image from the Dockerfile or docker-compose configuration. Prebuilds populate the [Dev Container image cache](/docs/ona/runners/devcontainer-image-cache), which speeds up subsequent builds.
* **Dev Container lifecycle commands**:
* `initializeCommand` - Runs before the container is created
* `onCreateCommand` - Runs when the container is created for the first time
* `updateContentCommand` - Runs when the container is created or updated
* **Prebuild tasks**: Any tasks in `.ona/config.yaml` configured with the `prebuild` trigger. Organization and project secrets are available during these tasks, but user secrets are not. By default, a failed task produces a warning but the prebuild still succeeds. Set [`prebuildRequiresSuccess: true`](/docs/ona/reference/ona-config-schema#requiring-task-success-in-prebuilds) on a task to fail the prebuild when the task doesn't succeed.
* **JetBrains warmup** (optional): When enabled, downloads and installs the JetBrains backend and runs the warmup command to build project indexes. See [JetBrains warmup](#jetbrains-warmup) for details.
### What doesn't run
The following do **not** run during prebuilds. They run when a user starts an environment:
* **Dev Container lifecycle commands**:
* `postCreateCommand`: runs after the environment is created
* `postStartCommand`: runs every time the environment starts
* `postAttachCommand`: runs when you attach to the environment
* **Tasks and services triggers**: Tasks and services with `postDevcontainerStart`, `postEnvironmentStart`, or `postMachineStart` triggers do not run during prebuilds. Only the `prebuild` trigger fires during prebuild execution. This separation is intentional. Prebuilds run without user context (no user secrets), so running a task during a prebuild is opt-in via the `prebuild` trigger.
When a user creates an environment from a prebuild, the normal triggers (`postDevcontainerStart`, `postEnvironmentStart`, etc.) fire as usual.
### What gets included in the snapshot
The prebuild snapshot captures the entire Dev Container filesystem: installed dependencies, built artifacts, downloaded assets, and all file system changes made during prebuild execution. Nothing is excluded.
Untracked git changes created during the prebuild are cleared when an environment starts. Ona fetches the latest changes from the remote repository, which resets uncommitted or untracked files. To persist generated files, add them to `.gitignore` or write them outside the workspace folder.
Prebuilds use the same [persistent storage](/docs/ona/environments/persistent-storage) model as regular environments.
## Benefits
* **Faster startup**: Skip dependency installation and build steps
* **Consistent environments**: All team members start from the same state
* **Lower resource usage**: Build once, use many times
## Runtime impact
Most prebuilds consume **5-10 minutes of runtime per project per day** across the entire organization. They run once daily.
**Example**: 20 engineers on a project, one 10-minute prebuild per day. Prebuilds account for about **2% of total runtime** while making every engineer faster.
Prebuilds trade a small amount of runtime to skip repetitive setup for your entire team.
## How prebuilds work
1. **Trigger**: A prebuild starts on schedule or manual trigger
2. **Environment creation**: Ona creates a temporary environment from your project's configuration
3. **Command execution**: Dev Container lifecycle commands and prebuild tasks run
4. **Snapshot**: Ona snapshots the environment once commands complete
5. **Cleanup**: The temporary environment is deleted
6. **Usage**: New environments start from the most recent successful snapshot
## Prebuild lifecycle
Prebuilds go through several phases:
* **Pending**: Prebuild created, waiting to start
* **Starting**: Environment is being created
* **Running**: Commands and tasks are executing
* **Stopping**: Commands completed, environment is stopping
* **Snapshotting**: Creating a snapshot of the environment
* **Completed**: Prebuild successful, snapshot available
* **Failed**: Prebuild encountered an error. This includes Dev Container image build failures and tasks with [`prebuildRequiresSuccess`](/docs/ona/reference/ona-config-schema#requiring-task-success-in-prebuilds) that did not succeed.
* **Cancelling**: Prebuild is being cancelled, cleanup in progress
* **Cancelled**: Prebuild was manually cancelled
## Secrets and authentication
During prebuild execution:
* **Organization secrets**: Available to all prebuilds
* **Project secrets**: Available to prebuilds for that project
* **User secrets**: Not available (prebuilds run without user context)
### Prebuild executor
The executor determines which identity clones the repository and runs the prebuild. Configure it in project settings.
* **User (default)**: The prebuild runs as the user who enabled prebuilds
* **Service account**: The prebuild runs as a [service account](/docs/ona/organizations/service-accounts), using the service account's SCM credentials
Regardless of executor, **no user secrets are used** during prebuilds. Only organization and project secrets are available.
When using a service account, configure SCM access on all runners where prebuilds run. See [Git authentication](/docs/ona/organizations/service-accounts#git-authentication) for setup.
Project admins can change the executor to themselves or a service account. If another user is the current executor, admins can leave it unchanged but cannot switch it to a different user.
**Best practice:** Use service accounts so prebuilds keep working regardless of individual user availability.
## Timeouts
| Timeout Type | Default | Range | Description |
| ---------------------- | ------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| **Prebuild execution** | 1 hour | 5 minutes - 2 hours | Time allowed for running the environment with Dev Container build/lifecycle commands and automation prebuild tasks (configurable per project) |
| **Snapshotting** | 4 hours | Fixed | Time allowed for creating the snapshot after prebuild execution completes |
| **Overall timeout** | 6 hours | Fixed | Catch-all timeout for the entire prebuild process, including environment creation, command execution, and snapshotting |
If a prebuild exceeds its timeout, it fails. The underlying environment is torn down immediately so you stop paying for the VM, while the prebuild logs remain viewable for the remainder of the prebuild's retention window.
## Prebuild retention
* Prebuilds are deleted after **7 days**
* Only the most recent successful prebuild per environment class is used
* Failed prebuild logs remain viewable for 7 days; the underlying environment is deleted as soon as the prebuild fails
## Pricing
### Ona Cloud
* **Environment usage**: Standard usage-based billing for the time the prebuild environment runs
* **Storage**: Prebuild snapshots are **free** (this may change)
### Enterprise (Your Cloud)
* **Environment usage**: You pay for compute resources used by the prebuild environment
* **Storage**: You pay for actual data stored in the snapshot. If you use 50 GB of a 100 GB volume, you are billed for 50 GB. Snapshots are stored as volume snapshots in your cloud provider (backed by S3).
See [Billing](/docs/ona/billing/overview) for details.
## Runner support
Prebuilds are supported on the latest version of every runner type:
* **Ona Cloud**: supported by default
* **AWS runners**: supported on the latest CloudFormation stack. See [Update an AWS runner](/docs/ona/runners/aws/update-runner#upgrade-runner-infrastructure)
* **GCP runners**: supported on the latest Terraform stack. See [Update a GCP runner](/docs/ona/runners/gcp/update-runner#updating-infrastructure)
If prebuilds are not available in your organization, upgrade your runner to pick them up.
## JetBrains warmup
JetBrains warmup pre-installs the JetBrains backend and builds project indexes during prebuilds. Users skip the download and indexing time when they open a JetBrains editor.
### What JetBrains warmup does
1. **Backend pre-installation**: Downloads and installs the JetBrains backend during the prebuild
2. **Index building**: Runs the warmup command to build project indexes (code analysis, symbol tables)
### Enabling JetBrains warmup
1. Navigate to your project settings
2. In the prebuild configuration section, enable **JetBrains warmup**
3. Configure [recommended editors](/docs/ona/projects/recommended-editors) to specify which JetBrains editors to warm up
### Warmup execution order
JetBrains warmup runs after all other prebuild tasks complete. This means dependencies are installed and build artifacts are generated before indexing begins.
## Use case: caching large file downloads
If your project downloads large assets (e.g. 20 GB+ of data files), configure a prebuild task to download them once. Subsequent environments start from the snapshot with the files already present, avoiding repeated downloads and reducing egress costs.
## Warm pools
For projects where even prebuild-based startup is too slow (e.g. large monorepos with big EBS volumes), [warm pools](/docs/ona/projects/warm-pools) keep pre-initialized EC2 instances running and ready to claim. This significantly reduces environment startup time by skipping instance provisioning and snapshot restoration. Warm pools require the Enterprise plan and an AWS runner.
## Limitations
* Prebuilds are tied to a specific environment class on a runner
* Only one prebuild per environment class is active at a time
* Only daily scheduling is available (more trigger options coming soon)
* Prebuilds cannot be triggered on every commit (coming soon)
## Next steps
* [Configure prebuilds for your project](/docs/ona/projects/prebuilds-setup)
* [View and manage prebuilds](/docs/ona/projects/prebuilds-management)
* [Enable warm pools](/docs/ona/projects/warm-pools) for faster startup times
* Learn about [Dev Container configuration](/docs/ona/configuration/devcontainer/overview)
* Explore [Tasks and Services](/docs/ona/configuration/tasks-and-services/overview)
# Managing prebuilds
Source: https://ona.com/docs/ona/projects/prebuilds-management
## View prebuilds
Navigate to your project settings and click the **Prebuilds** tab. All project members can view prebuilds and their logs.
Each prebuild shows:
* **Date & Time** - when the prebuild was created.
* **Class** - the environment class and runner used.
* **Triggered by / Ran as** - the trigger source (push, schedule, or manual) and the user it ran as.
* **Status & Duration** - the current phase (pending, running, snapshotting, completed, failed, cancelled) and elapsed time. During snapshotting, a completion percentage is shown when available from the cloud provider.
* **Snapshot Size** - the size of the resulting snapshot, shown once the prebuild completes.
## Configure prebuild settings
In the project **Settings** tab, the prebuild configuration section lets you:
* **Enable prebuilds** - turn prebuilds on or off for the project.
* **Select environment classes** - choose which environment classes to prebuild.
* **Schedule** - set the daily prebuild time (hour in UTC). Prebuilds start within the scheduled hour and may be delayed by up to 30 minutes because runs are staggered to spread cloud capacity requests.
* **Executor** - choose who runs prebuilds (yourself or a service account). The executor's SCM credentials are used to clone the repository.
* **Timeout** - set the maximum duration for a prebuild (5 minutes to 2 hours, defaults to 1 hour).
* **JetBrains warmup** - pre-install the JetBrains backend and build project indexes during prebuilds so JetBrains editors start faster. See [JetBrains warmup](/docs/ona/projects/prebuilds#jetbrains-warmup) for details.
## View logs
Click the actions menu on a prebuild row and select **Logs** to see Dev Container lifecycle command output, automation task logs, build progress, and error messages.
When troubleshooting failures, check logs for errors, verify required secrets are configured, and confirm commands do not require user interaction.
## Trigger prebuilds manually
Click the **Run Prebuild** button in the top right of your project settings to run prebuilds for all selected environment classes.
For specific environment classes, use the CLI:
```bash theme={null}
ona prebuild trigger --environment-class-id
```
## Cancel prebuilds
Cancel a running prebuild from the Prebuilds tab or via CLI:
```bash theme={null}
ona prebuild cancel
```
Cancelled prebuilds consume resources until cleanup completes.
## Bulk cancel and delete
Use the checkboxes on the Prebuilds tab to select multiple prebuilds at once, then choose an action from the bulk-action bar:
* **Cancel prebuilds** stops any in-progress prebuilds in the selection. Prebuilds that are already completed, failed, or cancelled are skipped.
* **Delete prebuilds** removes the selected prebuilds. New environments will not start from them. Existing environments that were created from these prebuilds keep running and are unaffected.
Bulk actions process each prebuild independently. The progress dialog shows per-item success or failure so you can see exactly which prebuilds were skipped or returned an error.
## CLI commands
```bash theme={null}
# List prebuilds
ona prebuild list --project-id
# Get prebuild details
ona prebuild get
# Delete a prebuild
ona prebuild delete
```
See the [CLI documentation](/docs/ona/integrations/cli) for configuration commands.
## Related
* [Prebuild concepts](/docs/ona/projects/prebuilds)
* [Setting up prebuilds](/docs/ona/projects/prebuilds-setup)
## Troubleshooting
Check logs for errors, verify secrets are configured at organization or project level, and confirm commands do not require user interaction.
Verify a successful prebuild exists for the environment class and is less than 7 days old.
Review logs for hanging commands, check timeout settings, or cancel and retry.
# Setup prebuilds
Source: https://ona.com/docs/ona/projects/prebuilds-setup
Configure prebuilds for your project to reduce environment startup times.
## Prerequisites
* Project user, editor, or admin role on the project
* An existing project with at least one environment class
* AWS or GCP Enterprise runner, or Ona Cloud
**AWS and GCP Enterprise runners**: Update to the latest infrastructure version before using prebuilds:
* **AWS**: [Upgrade your CloudFormation stack](/docs/ona/runners/aws/update-runner#upgrade-runner-infrastructure)
* **GCP**: [Update your Terraform stack](/docs/ona/runners/gcp/update-runner#updating-infrastructure)
## Enable prebuilds
### 1. Navigate to project settings
1. Go to your organization dashboard at [https://app.ona.com](https://app.ona.com)
2. Select your project from the projects list
### 2. Configure prebuild settings
In the project settings, the prebuild configuration section lets you:
1. **Enable prebuilds** for the project
2. **Select environment classes** to prebuild
3. **Configure the schedule** for automatic prebuild creation
4. **Configure the executor** to run prebuilds as yourself or a service account
5. **Set timeout** for prebuild execution
When you enable prebuilds, the daily schedule activates. Disabling prebuilds:
* Stops the daily schedule
* Prevents new environments from using existing snapshots
* Leaves existing snapshots until they expire (7 days)
You can run prebuilds manually at any time to create fresh snapshots after configuration changes or to retry failures.
### 3. Select environment classes
Check the boxes next to the environment classes you want to prebuild. Prebuilds run for each selected class on the configured schedule.
**Tip**: If your team primarily uses one or two classes (e.g., "Regular"), enable prebuilds only for those to keep costs low.
### 4. Configure the executor
Choose which identity runs your prebuilds:
* **User (default)**: Prebuilds run as the user who enabled them
* **Service account**: Prebuilds run as a [service account](/docs/ona/organizations/service-accounts), using the service account's SCM credentials
**When to use a service account:**
* Prebuilds keep working regardless of individual user availability
* Permissions stay consistent independent of user role changes
* Prebuild activity is attributed to a dedicated account
**Requirements for service accounts:**
* [Git authentication configured](/docs/ona/organizations/service-accounts#git-authentication) on all runners where prebuilds run
* The service account's Personal Access Token must have access to the project's repository
Regardless of executor, no user secrets are used during prebuilds. Only organization and project secrets are available.
Project admins can change the executor to themselves or a service account. If another user is the current executor, admins can leave it unchanged but cannot switch to a different user.
### 5. Configure the schedule
Set when prebuilds run:
1. **Daily schedule**: Choose the hour (UTC) when prebuilds trigger
2. **Recommended timing**: Schedule during off-hours so fresh prebuilds are ready when your team starts work
Prebuilds are created in batches during the scheduled hour to spread cloud capacity requests. Your prebuild will start within the scheduled hour, but not necessarily at the exact start of it. Expect up to 30 minutes of delay depending on how many projects share the same hour.
**Example**: If your team is in EST (UTC-5) and starts at 9 AM, schedule prebuilds for 1 PM UTC (8 AM EST).
### 6. Set timeout
Configure how long prebuilds can run before timing out. You can set the timeout in project settings under **Prebuild Environments → Times out after**, or via the CLI:
```bash theme={null}
ona project configure-prebuilds --enabled --timeout 90m
```
Set the timeout above your typical build duration with some buffer. If builds take 30 minutes, a 45-minute timeout works well.
See the [timeouts overview](/docs/ona/projects/prebuilds#timeouts) for limits and behavior.
### 7. Configure JetBrains warmup (optional)
If your team uses JetBrains editors, enable warmup to pre-install the backend and build project indexes during prebuilds:
1. In the prebuild configuration section, enable **JetBrains warmup**
2. Configure [recommended editors](/docs/ona/projects/recommended-editors) to specify which JetBrains editors to warm up
Warmup runs after all other prebuild tasks complete, so the project is built before indexing begins. Users skip the backend download and get prebuilt indexes for code navigation.
## Configure your Dev Container for prebuilds
Structure your Dev Container configuration so prebuilds handle the slow parts.
### Commands that run during prebuilds
Place time-consuming setup in these lifecycle hooks:
```json theme={null}
{
"initializeCommand": "echo 'Runs before container creation'",
"onCreateCommand": "npm install && npm run build",
"updateContentCommand": "npm install"
}
```
### Commands that run after prebuilds
Place user-specific or session-specific commands here:
```json theme={null}
{
"postCreateCommand": "echo 'Runs after container creation'",
"postStartCommand": "npm run dev",
"postAttachCommand": "echo 'Welcome!'"
}
```
## Configure tasks and services for prebuilds
Add the `prebuild` trigger to tasks that should run during prebuilds:
```yaml theme={null}
tasks:
seedDatabase:
name: Seed the database with test data
triggeredBy:
- prebuild
command: npm run db:seed
downloadAssets:
name: Download large asset files
triggeredBy:
- prebuild
command: ./scripts/download-assets.sh
```
Tasks with the `prebuild` trigger execute during prebuild creation alongside Dev Container lifecycle commands.
Organization and project secrets are available to tasks during prebuilds, but user secrets are not. Configure any credentials needed for prebuild tasks at the organization or project level.
### Choosing between `prebuild` and `postDevcontainerStart`
During a prebuild, **only** tasks with the `prebuild` trigger run. Other triggers like `postDevcontainerStart` do **not** fire during prebuilds. Prebuilds run without user context (no user secrets), so running a task during a prebuild is opt-in.
When a user creates an environment from a prebuild, `postDevcontainerStart` fires as usual.
| Scenario | Trigger to use |
| ----------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| Task should run during prebuilds only (e.g., download large assets once) | `prebuild` |
| Task should run when a user starts an environment (e.g., start a dev server) | `postDevcontainerStart` |
| Task should run during prebuilds *and* when the Dev Container is rebuilt (e.g., install dependencies) | Both `prebuild` and `postDevcontainerStart` |
**Example**: Install dependencies during prebuilds so the snapshot includes `node_modules`, and also when a user rebuilds their Dev Container (which creates a fresh container without the snapshot):
```yaml theme={null}
tasks:
install-deps:
name: Install dependencies
triggeredBy:
- prebuild
- postDevcontainerStart
command: npm ci
```
## Manually trigger a prebuild
### Via web UI
1. Open your project from the dashboard
2. Click the **Run Prebuild** button in the project header
This runs a prebuild for all selected environment classes. Use manual runs to test configuration changes, create fresh prebuilds after code changes, or prepare prebuilds before the scheduled time.
### Via CLI
Run prebuilds for specific environment classes:
```bash theme={null}
ona prebuild trigger --environment-class-id
```
## Verify your setup
After enabling prebuilds:
1. Run a manual prebuild and verify it completes
2. Check the prebuild logs for errors
3. Create a new environment and confirm it starts from the prebuild
4. Verify the schedule matches your timezone
If the prebuild fails, check logs for error messages and verify that required secrets are configured at the organization or project level.
## Best practices
### Speed and cost
Install only what development needs. Schedule prebuilds during off-hours so fresh snapshots are ready when your team starts. Start with one or two commonly used environment classes, then expand based on usage.
### Structuring commands
Place stable, time-consuming operations in prebuild commands: dependency installation, database seeding, asset downloads. Reserve `postCreateCommand` for dynamic operations like starting dev servers or user-specific setup. Keep all commands idempotent.
### Managing secrets
Use organization secrets for shared build credentials and project secrets for project-specific credentials. User secrets are not available during prebuilds.
## Next steps
* [View and manage your prebuilds](/docs/ona/projects/prebuilds-management)
* [Enable warm pools](/docs/ona/projects/warm-pools) for faster startup times (Enterprise, AWS only)
* [Understand prebuild concepts](/docs/ona/projects/prebuilds)
* [Optimize your Dev Container configuration](/docs/ona/configuration/devcontainer/optimizing-startup-times)
* [Learn about Tasks and Services](/docs/ona/configuration/tasks-and-services/overview)
## Troubleshooting
Verify prebuilds are enabled in project settings.
Check logs for errors, verify secrets are configured, and confirm commands do not require user interaction. If builds time out, increase the timeout in project settings or via CLI.
Confirm a successful prebuild exists for the environment class and is less than 7 days old.
Move user-specific or session-specific commands to `postCreateCommand`. Verify file permissions are correct after the snapshot.
See [Managing prebuilds](/docs/ona/projects/prebuilds-management) for more troubleshooting.
# Project secrets
Source: https://ona.com/docs/ona/projects/project-secrets
Project secrets are scoped to a single project. Anyone who launches an environment from the project gets these secrets injected automatically. Use them for credentials the whole team needs for that repository (API keys, service accounts, registry access) without exposing them to other projects in the organization.
**Project secrets have middle precedence.** They override organization secrets but can be overridden by user secrets. Teams set project defaults while individuals can still customize.
## Common uses
Project secrets are the right default for credentials tied to one repository or workflow.
Typical examples:
* API keys for services used by one codebase
* shared test credentials
* project-specific registry access
* configuration values that should travel with the project rather than the whole organization
## Manage project secrets
Navigate to **Project → Secrets**.
From here you can create, edit, and delete secrets. Each secret can be an [environment variable](/docs/ona/configuration/secrets/environment-variables), [file](/docs/ona/configuration/secrets/files), or [container registry credential](/docs/ona/configuration/secrets/container-registry-secret).
## When to use project secrets
* **Shared service accounts**: Database credentials, API keys for project-specific services
* **Project configuration**: Environment-specific settings the whole team needs
* **Container registry access**: Private images for this project's Dev Container
For personal credentials like your own Linear or GitHub token, use [user secrets](/docs/ona/configuration/secrets/user-secrets) instead.
## How project secrets affect environments and automations
Project secrets are available to environments launched from that project, including automation runs that create environments from the project. That makes them the best place for shared defaults a project-backed workflow depends on.
If the same secret also exists at organization scope, the project secret takes precedence for this project.
## Related
* [How secrets work](/docs/ona/configuration/secrets/overview)
* [User secrets](/docs/ona/configuration/secrets/user-secrets)
* [Organization secrets](/docs/ona/organizations/organization-secrets)
# Project visibility
Source: https://ona.com/docs/ona/projects/project-sharing
When you create a project, you become its admin. Default visibility depends on your organization's tier:
* **Enterprise tier**: projects are visible to admins only by default, until access is granted to specific groups or users via the Share dialog
* **All other tiers**: projects are shared with the entire organization by default
On the Enterprise tier, the Share dialog also lets you grant access to specific groups and individual users. For more on this, see [Sharing resources](/docs/ona/organizations/sharing-resources).
To give a team admin access to **all** projects in the organization, assign the [Projects Admin](/docs/ona/organizations/organization-roles) role to their group.
## What visibility controls
Project visibility controls who can discover a project in the UI and who can use it to create environments. It does not change who can access the underlying repository outside Ona, and it does not hide a project from organization admins.
In practice, visibility answers three questions:
* who can see the project
* who can create environments from it
* whether the project is broadly available or limited to a smaller team
## Change visibility
1. Open the project from your dashboard
2. Click the **Share** button in the project header
3. Under **General access**, select:
* **Everyone in **: all members can see and use the project
* **Only groups and users with access**: restricted to explicitly added groups and users
Projects cannot be hidden from admins.
## When to use each mode
* **Everyone in **: use this for common services, shared internal platforms, templates, and repositories many engineers need.
* **Only groups and users with access**: use this while a project is being prepared, when access should be tightly controlled, or when the project should only be available to specific teams.
If you need more control, use [Sharing resources](/docs/ona/organizations/sharing-resources) to grant access to specific users or groups.
## Create an environment from a shared project
Once a project is shared with you, you can create an environment from it directly. On the **Projects** page, click **Create Environment** on the project card. The environment inherits the project's repository, secrets, and configuration.
## Access dependencies
Project access alone is not always enough to create an environment. A user also needs access to at least one runner used by that project.
If someone can see a project but cannot start an environment from it, check:
* whether the project is shared with them
* whether a compatible runner is shared with them
* whether organization policies restrict environment creation
## Related
* [Create your first project](/docs/ona/create-first-project)
* [Sharing resources](/docs/ona/organizations/sharing-resources)
* [Organization roles](/docs/ona/organizations/organization-roles)
# Warm Pools
Source: https://ona.com/docs/ona/projects/warm-pools
Available on the Enterprise plan. Supported on [AWS](/docs/ona/runners/aws/overview) and [GCP](/docs/ona/runners/gcp/overview) runners. [Contact sales](https://ona.com/contact/sales) to learn more.
Warm pools keep pre-initialized instances ready to claim. When a user creates an environment, Ona assigns a warm instance instead of launching a new one, reducing startup time from minutes to seconds.
The pool scales dynamically between a minimum and maximum size based on demand. It scales up during peak hours and back down (optionally to zero) when idle.
## When to use warm pools
Warm pools are most effective for:
* **Large or monorepo projects** where snapshot restoration adds noticeable startup latency. Instances lazy-load data from the prebuild snapshot on first boot, and larger volumes take longer to fully hydrate. For these projects, warm pools can cut startup time from minutes to around 10 seconds.
* **Smaller projects with many users** where prebuilds already bring startup to 30-50 seconds. Warm pools can reduce this further to around 10 seconds. Whether the cost is justified depends on how many engineers use the project and how often they create new environments versus reusing existing ones.
* **Latency-sensitive workflows** where every second of startup time matters (e.g. PR review environments, demo environments).
Without warm pools, each environment launch provisions a new instance and restores the prebuild snapshot. With warm pools, the instance is already running and the snapshot is already loaded, skipping the most time-consuming parts of startup.
Actual startup time depends on your devcontainer configuration. Dotfiles installation and post-prebuild lifecycle hooks (`postCreateCommand`, `postStartCommand`, `postAttachCommand`) still run when the environment starts. Optimize these commands for the fastest experience.
## How it works
1. You enable a warm pool for a project and environment class, specifying a minimum and maximum pool size.
2. The runner launches instances from the latest prebuild snapshot, scaling between the minimum and maximum pool size.
3. The pool scales dynamically between your configured minimum and maximum based on demand (see [Dynamic scaling](#dynamic-scaling)).
4. When a user creates an environment, Ona claims a warm instance from the pool instead of launching a new one. The pool immediately begins replenishing.
5. When a new prebuild completes, the pool rotates instances to use the new snapshot.
Instances can be claimed even while still initializing. A partially warmed instance is still faster than a cold start because the EC2 instance is already running and the snapshot is partially loaded.
## Dynamic scaling
Warm pools scale automatically based on demand. The runner monitors how frequently instances are claimed and adjusts the number of running instances accordingly. It scales up when environments are being created (by engineers, automations, or agents) and scales back down when demand drops.
* **Scale-out** happens when sustained demand exceeds what the current running instances can serve. Stopped instances are started to meet demand (see [Stopped instances](#stopped-instances)), so scaling out takes roughly 1–2 minutes rather than the 5+ minutes of a cold boot.
* **Scale-in** happens when demand drops. The pool waits for demand to stay low before removing instances, so brief idle periods don't cause unnecessary churn.
* The pool never scales below `min-size` or above `max-size`.
### Stopped instances
In addition to running instances, the pool maintains **stopped instances** that are pre-provisioned but not actively running. These act as a buffer for fast scale-out: when demand increases, a stopped instance can be started in roughly 1–2 minutes instead of provisioning a new one from scratch (\~5 minutes).
The number of stopped instances equals the remaining capacity between the current number of running instances and `max-size`. For example, with `max-size = 5` and 3 running instances, there are 2 stopped instances ready to start.
Stopped instances save on cost because you only pay for their disk storage, not compute. This means the pool can maintain headroom for burst demand without paying for idle running instances.
Stopped instances only help when the pool scales *out* (adding more running instances). They do not reduce startup time for the first environment when the pool is scaled to zero, because there are no running instances to claim. In that case, the first environment is a cold start.
### Scale to zero
Setting `min-size` to `0` allows the pool to scale down to zero running instances when there is no demand. This is useful for reducing costs during off-hours, weekends, or for projects with intermittent usage.
**Tradeoffs:**
| | min-size = 0 | min-size ≥ 1 |
| -------------------------------- | ---------------------------------------------- | ---------------------------------- |
| **Off-hours cost** | No running instances, no compute cost | At least one instance running 24/7 |
| **First environment after idle** | Cold start (similar to not having a warm pool) | Near-instant (\~10 seconds) |
| **Subsequent environments** | Near-instant once the pool has scaled up | Near-instant |
**How quickly does the pool scale down to zero?**
The pool requires at least **30 minutes** of inactivity (no environments created) before it begins scaling down to zero. This idle guard prevents aggressive scale-down during brief lulls, such as a lunch break. After the idle guard expires, the cloud provider completes the scale-in shortly after.
Use `min-size = 0` for projects where occasional slower startups are acceptable in exchange for lower cost. Use `min-size = 1` (or higher) for projects where instant startup is always expected.
## Prerequisites
* [Enterprise plan](https://ona.com/pricing)
* [Prebuilds enabled](/docs/ona/projects/prebuilds-setup) for the project
* A runner with warm pool support:
* **AWS**: latest infrastructure version. [Upgrade your CloudFormation stack](/docs/ona/runners/aws/update-runner#upgrade-runner-infrastructure) if you haven't already.
* **GCP**: latest Terraform module version. [Upgrade your Terraform module](/docs/ona/runners/gcp/update-runner#updating-infrastructure) if you haven't already.
* At least one successful prebuild for the environment class
* **Project admin** role on the project
## Enable warm pools
Only **project admins** can configure warm pools.
### Via the dashboard
1. Navigate to your project settings
2. In the **Prebuilds** section, find the environment class list
3. Expand an environment class row. A **Warm Pool** toggle appears below each class that has prebuilds enabled
4. Toggle **Warm Pool** on
5. Set the **Min Size** and **Max Size** to define the scaling range
The warm pool toggle only appears for environment classes on runners that support warm pools and have prebuilds enabled.
### Via the CLI
```bash theme={null}
# Create a warm pool with scaling bounds
ona prebuild warm-pool create \
--environment-class-id \
--min-size 1 \
--max-size 3
# Create a warm pool that can scale to zero
ona prebuild warm-pool create \
--environment-class-id \
--min-size 0 \
--max-size 3
# List warm pools for a project
ona prebuild warm-pool list --project-id
# Check warm pool status
ona prebuild warm-pool get
# Update scaling bounds
ona prebuild warm-pool update --min-size 0 --max-size 5
# Delete a warm pool
ona prebuild warm-pool delete
```
All commands support `--format json`, `--format yaml`, and `--format table` output.
## Pool lifecycle
Warm pools go through these phases:
| Phase | Description |
| ------------ | ------------------------------------------------------------------------------------------------------ |
| **Pending** | Pool created, waiting for a prebuild snapshot to be assigned |
| **Ready** | Instances are available for claiming (running count may vary based on current demand) |
| **Degraded** | The runner reported a problem (e.g. failed to launch instances). Check the failure message for details |
| **Deleting** | Pool is being deleted, instances are draining |
| **Deleted** | All instances terminated, cleanup complete |
When you disable prebuilds or delete the warm pool, instances drain gracefully. The pool enters the **Deleting** phase and transitions to **Deleted** once all instances are terminated.
## Cost
Warm pool instances are regular compute instances in your cloud account. With dynamic scaling, you pay only for instances that are actually running. The pool scales down during low-demand periods.
No Ona credits are consumed. You pay only for the cloud infrastructure.
**Running instances** (actively serving or waiting to be claimed) are billed at standard on-demand rates. **Stopped instances** (pre-provisioned for fast scale-out) are not billed for compute. You pay only for their attached storage.
Start with `min-size = 1` and `max-size = 2`. Increase `max-size` if your team frequently hits cold starts during peak hours. Switch to `min-size = 0` once you're comfortable with the startup tradeoff during off-hours.
### AWS cost estimates
Costs depend on the [environment class](/docs/ona/runners/aws/environment-classes) (instance type) and AWS region. Estimates below use `us-east-1` on-demand pricing:
| Environment Class | Instance Type | Approx. cost per running instance/month |
| ----------------- | --------------------------- | --------------------------------------- |
| Small | m6i.large (2 vCPU, 8 GB) | \~\$70 |
| Regular | m6i.xlarge (4 vCPU, 16 GB) | \~\$140 |
| Large | m6i.2xlarge (8 vCPU, 32 GB) | \~\$280 |
**Example**: A warm pool configured with `min-size = 0` and `max-size = 3` using `m6i.xlarge` (Regular) instances might average 1 running instance during business hours and 0 outside of them. That costs roughly **\$70–100/month** instead of \$280/month for a fixed pool of 2.
EBS volume costs are additional but typically small relative to compute, roughly \$0.08/GB/month for gp3 volumes.
Filter AWS Cost Explorer by the tag `gitpod.dev/warm-pool` to isolate warm pool instance costs from regular environment costs. See [Costs & budgeting](/docs/ona/runners/aws/aws-runner-costs) for general cost tracking.
### GCP cost estimates
Costs depend on the machine type and GCP region. Estimates below use `us-central1` on-demand pricing:
| Machine Type | vCPUs | Memory | Approx. cost per running instance/month |
| -------------- | ----- | ------ | --------------------------------------- |
| n2d-standard-2 | 2 | 8 GB | \~\$65 |
| n2d-standard-4 | 4 | 16 GB | \~\$130 |
| n2d-standard-8 | 8 | 32 GB | \~\$260 |
Persistent disk costs are additional but typically small relative to compute. See [Costs & budgeting](/docs/ona/runners/gcp/gcp-runner-costs) for general cost tracking.
## Sizing guidance
| Team size | Recommended min | Recommended max | Rationale |
| --------------- | --------------- | --------------- | ---------------------------------------------------------- |
| 1-10 engineers | 0-1 | 2 | Low concurrency; scale-to-zero saves cost for small teams |
| 10-30 engineers | 1 | 3 | Keeps one instance always ready; scales for burst patterns |
| 30+ engineers | 1-2 | 3-5 | Higher baseline for peak-hour concurrency |
These are starting points. The right configuration depends on how large the project is (larger projects take longer to replenish), how often engineers create new environments versus reusing existing ones, and whether off-hours cost savings matter. Monitor your pool's claim hit rate and adjust.
## Viewing warm pool usage
You can view warm pools configured in your organization from the dashboard or CLI.
Organization admins see all warm pools. Other members only see warm pools for projects they have access to.
### Via the dashboard
Navigate to a runner's details page and select the **Warm Pools** tab. This shows all warm pools on that runner, including the associated project, environment class, pool size, and current phase.
### Via the CLI
```bash theme={null}
# List all warm pools in the organization
ona prebuild warm-pool list
# Filter by a specific project
ona prebuild warm-pool list --project-id
# Filter by environment class
ona prebuild warm-pool list --environment-class-id
# Output as JSON for scripting
ona prebuild warm-pool list --format json
# Get details for a specific warm pool
ona prebuild warm-pool get
```
## Monitoring
Warm pools expose Prometheus metrics through the runner's metrics endpoint. Use these to track pool utilization, claim hit rate, and scaling behavior. See [Custom metrics pipeline](/docs/ona/runners/monitoring-and-metrics#warm-pools-warm_pool_) for setup instructions and the full list of available metrics.
Key metrics to watch:
* **`warm_pool_claims_total`**: Track the `instance_not_found` result to see how often users hit cold starts. If this happens frequently, increase `max-size` or `min-size` (the pool may be scaling down too aggressively).
* **`warm_pool_claim_instance_age_seconds`**: Shows how long instances waited before being claimed. Very short ages may indicate the pool is undersized.
* **`warm_pool_instances_by_state`**: Compare running vs stopped instance counts to verify scaling behavior.
## Limitations
* **No spot instances (AWS).** Warm pools require on-demand environment classes. If you enable a warm pool on a [spot environment class](/docs/ona/runners/aws/environment-classes#spot-instance-reclamation), the pool enters the [**Degraded** phase](#pool-lifecycle). Use a non-spot class instead.
## Related
* [Prebuilds overview](/docs/ona/projects/prebuilds)
* [Setting up prebuilds](/docs/ona/projects/prebuilds-setup)
* [AWS environment classes](/docs/ona/runners/aws/environment-classes)
* [AWS runner costs](/docs/ona/runners/aws/aws-runner-costs)
* [Upgrade AWS runner infrastructure](/docs/ona/runners/aws/update-runner#upgrade-runner-infrastructure)
* [GCP runner costs](/docs/ona/runners/gcp/gcp-runner-costs)
* [Upgrade GCP runner infrastructure](/docs/ona/runners/gcp/update-runner#updating-infrastructure)
# Quickstart
Source: https://ona.com/docs/ona/quickstart
Get up and running with Ona in less than 5 minutes.
By the end of this guide you'll have an environment running your code and an agent working on your first task.
Get started →
Want to run Ona in your own VPC? [Get in touch](https://ona.com/contact/sales) to set up a self-hosted deployment on [AWS](/docs/ona/runners/aws/overview) or [GCP](/docs/ona/runners/gcp/overview).
## Prerequisites
* An [Ona account](https://app.ona.com)
* Select your [Git provider](/docs/ona/source-control/overview)
## 1. Create a project
A project connects a repository to Ona, giving you a single place to manage environments, Automations, secrets, and team access for that codebase. Once a project exists, anyone on your team can spin up a fully configured environment in seconds. No local setup, no "works on my machine" problems.
Go to **Projects > New Project**, select your Git provider, and pick a repository. See [Create your first project](/docs/ona/create-first-project) for a detailed walkthrough.
Speed up environment starts with [prebuilds](/docs/ona/projects/prebuilds) and [warm pools](/docs/ona/projects/warm-pools) so environments are ready before anyone needs them.
## 2. Start an environment
From your project, click **Create Environment**. Ona clones the repository into a container and provisions a development environment. Once the environment is running, you can open VS Code in your browser, talk to Ona, or [connect your preferred IDE](/docs/ona/editors/overview).
If the environment stays in a loading state for more than two minutes, check that your repository is accessible and that your Git provider is connected under **Settings > Git Authentications**. See [troubleshooting](/docs/ona/troubleshooting) for more.
## 3. Talk to Ona
Once your environment is running, you have a session with Ona. Describe what you want to build, fix, or explore:
Paste one of these prompts into Ona:
Explore a codebase
"Explain the architecture of this codebase"
Paste into Ona
Fix failing tests
"Fix the failing tests in the auth module"
Paste into Ona
Add a feature
"Add a new API endpoint for user preferences, following the patterns in the existing code"
Paste into Ona
Review pull requests
"Review the open pull requests and leave detailed code review comments"
Paste into Ona
If you've connected [Linear](/docs/ona/integrations/configure-linear) or [Jira](/docs/ona/integrations/configure-atlassian), you can ask Ona to pick up tickets directly:
Pick up a Linear ticket
"Pick up the next ticket assigned to me in Linear and start working on it"
Paste into Ona
Implement a Jira ticket
"Look at PROJ-142 in Jira and implement what's described"
Paste into Ona
## 4. Optimize your environment
Ona works out of the box with a default image, but you'll get better results with a configured environment. You can set this up manually or let Ona do it. It will analyze your repository and generate a `devcontainer.json` and `.ona/config.yaml` tailored to your codebase.
Open Ona, then paste the prompt below if you want Ona to generate a starter configuration for the current environment.
Open Ona →
```text theme={null}
Create a high-quality, fully working "development environment as code" configuration for the current environment.
The setup must work for:
- Ona development environments, which use DevContainer configurations.
- All Git repositories mounted under the DevContainer workspace.
Required Process
1. Read the documentation to fully understand:
- Ona tasks and services, secrets, environment variables, CLI, and prebuilds.
- DevContainer fundamentals and how they integrate with Ona and VS Code.
2. Analyze the source code and identify:
- Documentation on dev setup or contribution guidelines.
- Configuration files for containers, IDEs, build tools, environment variables, etc.
3. Update all necessary files, including:
- devcontainer.json
- Ona tasks and services
4. Run the Acceptance Tests and iterate until they pass.
Success Criteria
- The DevContainer includes all tools needed to work with any file in any repo.
- Ona services exist for every service required to run any app.
- Ona tasks exist for all standard development workflows.
- If an app exposes a TCP port, the DevContainer must forward it.
- The DevContainer installs all VS Code extensions necessary to work effectively.
Allowed Sources
- Ona documentation: https://ona.com/docs/llms.txt
- DevContainer documentation: https://containers.dev/
- DevContainers in VS Code: https://code.visualstudio.com/docs/devcontainers/containers
- DevContainer base images: https://hub.docker.com/r/microsoft/devcontainers
- Any publicly available DevContainer features
```
See [configure your environment](/docs/ona/configuration/devcontainer/getting-started) for a full reference on manual configuration.
## 5. Run agents in the background
Start multiple tasks from the home page using **Cmd+Enter** (Ctrl+Enter on Windows/Linux). Each task gets its own environment, so agents work in parallel without file conflicts.
When you're ready to automate that on a schedule, set up [Automations](/docs/ona/create-first-automation) to run agents on triggers like new issues or pull requests:
## Tips
* **Be specific.** Describe the exact symptom and location rather than saying "fix the bug." See [be explicit](/docs/ona/best-practices#be-explicit).
* **Plan first.** For complex tasks, ask Ona to plan before implementing. See [plan before building](/docs/ona/best-practices#plan-before-building).
* **Commit often.** Ask Ona to commit working changes as checkpoints. See [commit early, commit often](/docs/ona/best-practices#commit-early-commit-often).
## Next steps
* [Best practices](/docs/ona/best-practices) for writing effective prompts and working with agents
* [Configure your environment](/docs/ona/configuration/devcontainer/getting-started) with Dev Containers, tasks, and services
* [Connect integrations](/docs/ona/integrations/overview) like Linear, Jira, Slack, and Sentry
* [Set up automations](/docs/ona/automations/configure-automations) to run agents on schedules and triggers
* [Teach agents your codebase](/docs/ona/agents-md) with AGENTS.md
# Organization-level skills
Source: https://ona.com/docs/ona/skills
Codify your organization's best practices into reusable skills that agents can discover and anyone can run.
Your best engineers have prompts that work - ways of reviewing code, writing tests, or debugging issues that they've refined over time. Skills let you capture that expertise and share it with everyone.
Skills are reusable prompts that the agent can discover and use proactively when relevant. They can optionally be made available as slash commands, so users can also invoke them manually by typing `/` in the chat.
## Why this matters
Without shared skills, quality varies. One developer's code review catches security issues; another's misses them. One person knows how to write tests that actually test behavior; others write tests that only hit coverage targets.
With skills:
* **Expertise scales**: A senior engineer's review checklist becomes available to the whole team
* **Quality standardizes**: Everyone follows the same thorough process
* **Onboarding accelerates**: New team members immediately have access to proven workflows
* **Agents get smarter**: Skills are discoverable by the agent, so it can apply them proactively without being asked
## What a great skill looks like
Here's a real example - a code review skill that captures one engineer's review philosophy:
```markdown theme={null}
/review-like-mads
You are reviewing code changes with Mads Hartmann's perspective. Apply his review philosophy systematically:
## Design System First
- **Theme compatibility**: Works in light/dark AND old/new themes?
- **Semantic tokens**: Replace hardcoded colors with `border-subtle`, `surface-glass`
- **Visual evidence**: Request screenshots/videos if missing
- **Design alignment**: Matches Figma specs?
## Aggressive Cleanup
- **Remove unused**: Components, imports, files, commented code
- **Consolidate**: Similar components that could be unified
- **File organization**: Components in right locations?
## Technical Excellence
- **React patterns**: Proper `forwardRef`, `useImperativeHandle`, TypeScript
- **Component reuse**: Composing existing vs creating new
- **Accessibility**: ARIA, keyboard nav, screen readers
## Red Flags
- Hardcoded colors (`#fff`, `rgb()`)
- Duplicate patterns
- Missing visual docs
- Poor TypeScript
**Priority order**: Design system consistency → Code cleanliness → Component reusability → Technical implementation → Test coverage
```
Now anyone can type `/review-like-mads` and get a review with that level of rigor. The agent can also apply this skill on its own when it detects a code review task.
## More examples
| Skill | What it codifies |
| ------------------- | ---------------------------------------------------- |
| `/security-review` | Your security team's checklist for reviewing PRs |
| `/write-tests` | How your team writes tests that actually catch bugs |
| `/explain-this` | Your standard for documentation and code explanation |
| `/debug-strategy` | Your senior engineer's approach to debugging |
| `/deploy-checklist` | Everything to verify before shipping |
## Create your first skill
1. Go to [Settings > Agents > Skills](https://app.ona.com/settings/agent-skills)
2. Click **New Skill**
3. Configure:
* **Name**: What appears in the skill list (e.g., "Review like Mads")
* **Description**: When to use it
* **Prompt**: The full prompt text
* **Available as slash command**: Toggle on if you want users to invoke it with a `/trigger`
* **Command trigger**: The slash trigger (e.g., `review-like-mads`). Only shown when the slash command toggle is on
4. Click **Create Skill**
## Using skills
Skills work in two ways:
1. **Proactive discovery**: The agent automatically discovers skills and applies them when a task matches. No user action needed.
2. **Slash commands**: For skills with a command trigger, type `/` in the agent prompt to see available commands. Start typing to filter, then select with arrow keys or click.
You can add context after a slash command:
```
/review-like-mads
Focus especially on the authentication changes in src/auth/
```
The agent combines the skill's prompt with the additional context you provide.
## Migrating legacy commands
Existing slash commands created before skills were introduced appear as **Legacy Commands** in the settings page. They continue to work as before, but won't be discovered proactively by the agent.
To migrate a legacy command to a skill, click **Edit** on the command card and use the **Migrate to Skill** button in the banner. Migration preserves the slash command trigger while enabling proactive discovery.
## Tips for good skills
**Capture real expertise**: Base skills on how your best people actually work, not theoretical ideals.
**Be specific**: "Security Review" is better than "Review". Include the actual checklist, not "check for security issues."
**Include priorities**: Tell agents what matters most. "Focus on X before Y" helps them make tradeoffs.
**Update over time**: When someone catches something your skill missed, add it to the prompt.
## Example skills we use at Ona
These are real skills from our own workflow. They show what a well-structured skill looks like at scale.
Automates the full PR lifecycle from diff to merge-ready. The skill:
1. Cleans up code and runs formatters/linters
2. Detects linked Linear issues automatically from branch names
3. Creates a branch using your initials and a short description
4. Commits with Conventional Commits format
5. Opens a draft PR using your repo's PR template
6. Auto-categorizes for the changelog (feature, improvement, fix, or skip)
7. Cross-references documentation and runs a docs content review
8. Posts a summary and asks for changelog confirmation
The skill handles edge cases like feature-flag detection (auto-skips changelog for flagged work), in-progress feature detection across related PRs, and separate docs PRs when code changes need documentation updates.
PR workflow skill that gathers context, reads diffs, posts comments, and submits reviews. The skill:
1. Gathers PR metadata, diffs, existing reviews, and CI status
2. Fetches context from Linear (linked issues), GitHub (discussions), and Notion (design docs)
3. Delegates code quality analysis to a separate `review` skill that detects scope (backend Go, frontend React/TS, or mixed) and loads the appropriate checklist
4. Classifies findings by severity: `[P0]` Must fix, `[P1]` Should fix, `[P2]` Suggestion
5. Posts inline comments on specific lines with actionable fixes
6. Submits formal PR reviews (approve, request changes, or comment) via the GitHub API
7. Runs documentation review and product principles checks on frontend PRs
8. Auto-applies changelog labels if missing
Generates changelog entries from merged PRs in two modes: **weekly** (default) and **major** (standalone feature launch page).
For weekly changelogs, the skill:
1. Finds the boundary using git tags from the previous changelog run
2. Collects all merged PRs since the boundary via GitHub
3. Classifies each PR as New, Improvement, Bug fix, or Skip using labels, commit types, and LLM analysis
4. Filters out internal-only changes, feature-flagged work, and infrastructure PRs
5. Picks a headline feature and generates a 2-4 sentence description
6. Produces a Mintlify `Update` block with the headline, screenshot placeholder, and collapsible accordion sections
7. Opens a draft PR with the entry
All prose follows the `technical-writing` and `blog-writing` skill rules. The skill bans internal jargon (like "management plane", "Ent schema", "orchestrator") and rewrites everything from the user's perspective.
Finds flaky Go tests and CI build failures on main, diagnoses root causes, fixes what's mechanical, and raises individual PRs per fix. The skill:
1. Queries Honeycomb for Go test failures on main (last 24h and 7d trend)
2. Queries Honeycomb and GitHub Actions for CI build failures
3. Triages and ranks failures by frequency, impact, and fixability
4. For each flaky test, diagnoses the root cause (race conditions, shared state, non-deterministic ordering, testcontainer lifecycle, etc.)
5. Applies mechanical fixes under 20 lines, only proceeding when the root cause is clear
6. Runs the full test package 3 times with `-race` to verify stability
7. Opens individual ready-for-review PRs with re-run evidence
The skill follows a strict confidence gate: if the fix exceeds 20 lines, changes test semantics, or has an unclear root cause, it skips and logs the reason.
A style guide that ensures consistent tone and structure across all developer-facing content. Key principles:
* **Bottom line up front**: If the reader stops after the first paragraph, they should have what they need
* **Show, don't tell**: Prefer code examples over explanations, prompts over tutorials
* **Diataxis classification**: Every page belongs to exactly one type (tutorial, how-to guide, reference, or explanation)
* **Verify against source code**: Every claim must match the current code. When docs and code disagree, the code is right
* **Agent-ready**: Write docs that work as context for coding agents. Structure content so an agent can find the right page, extract the answer, and act on it
The skill includes a review checklist covering Diataxis type, code verification, link checking, heading quality, tier labeling, and messaging anti-patterns.
Query distributed tracing data across production, CI, and development environments. The skill documents:
* **Production datasets**: Backend API traces, EC2/GCP runner traces, and supervisor (in-environment) traces
* **CI datasets**: GitHub Actions workflow traces (via Thoth), Leeway build traces with Go test results
* **Key columns**: Environment IDs, organization IDs, RPC error codes, startup durations, test results, cache status
* **Example queries**: Environment startup duration, slowest RPC endpoints, failed builds, flaky test detection, supervisor setup times
The skill also includes instructions for constructing direct Honeycomb URLs so users can explore interactively, and documents gotchas like the attribute split across parent/child spans for startup traces.
## Next steps
* [Teach agents your codebase](/docs/ona/agents-md) with [AGENTS.md](/docs/ona/agents-md) and [Skills](/docs/ona/agents-md#skills-for-repository-specific-workflows)
* [Configure integrations](/docs/ona/integrations/overview) to connect agents with your project management
# Azure DevOps
Source: https://ona.com/docs/ona/source-control/azuredevops
Configure Azure DevOps as a source control provider for your Ona environments.
Azure DevOps is supported on [Self-Hosted Runners](/docs/ona/runners/aws/overview). Set up the integration during runner creation or in runner settings. Self-hosted Azure DevOps instances are supported by changing the Host during setup.
Azure DevOps is not available on Ona Cloud. Creating an environment from an Azure DevOps repository there fails with: `Ona Cloud (US01) requires authentication with Source Control - the SCM integration for host dev.azure.com is not configured`.
## Configuring Azure DevOps Access
If Azure DevOps is already set up on your runner, skip to [Authorizing Azure DevOps Access](#authorizing-azure-devops-access).
### Self-Hosted Runners
For self-hosted runners (like AWS), Azure DevOps integration is configured during runner creation or in the runner settings.
There are two ways to integrate with Azure DevOps. Both can be used simultaneously:
1. **OAuth App (Recommended):** Using a Microsoft Entra ID OAuth app allows users to sign in more quickly. You'll need to set up an OAuth app within Microsoft Entra ID.
2. **Personal Access Token (PAT):** Each user will need to create a Personal Access Token. They will be provided with a deep link to do so on their first environment creation.
For Azure DevOps, allow outbound HTTPS connections from your runner to `app.vssps.visualstudio.com` in your firewall, proxy, or egress filtering rules. Ona uses this Azure DevOps identity endpoint to validate the user's OAuth or PAT credentials and resolve the Azure DevOps profile before the runner can access repositories on that user's behalf.
This request is made by the runner, not by a user's browser, and it is separate from Git or REST traffic to `dev.azure.com`. If the endpoint is blocked, Azure DevOps authorization can fail even when repository URLs are otherwise reachable.
#### Using OAuth
OAuth requires a [Microsoft Entra ID](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/entra-oauth?view=azure-devops) app registration. You will set up the app in Azure, then enter its credentials in Ona.
**Step 1: Create the Entra ID app registration**
1. Go to the [Azure Portal](https://portal.azure.com) and navigate to **Microsoft Entra ID > App registrations**.
2. Click **New registration** and provide a name (e.g., "Ona Azure DevOps Integration").
3. Note the *Client ID* from the **Overview** page.
4. Note the *Issuer URL* from **Overview > Endpoints**. Use the v2.0 URL, e.g. `https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0`.
**Step 2: Configure authentication**
1. In your app registration, go to **Manage > Authentication**.
2. Ensure **Web** platform is selected and paste the callback URL from the Ona configuration dialog.
3. Enable **ID tokens** under *Implicit grant and hybrid flows*.
**Step 3: Create a client secret**
1. Navigate to **Manage > Certificates & secrets**.
2. Click **New client secret**, add a description, and set expiration as needed.
3. Copy the secret **Value** immediately (it is only shown once).
**Step 4: Configure API permissions**
Go to **Manage > API permissions** and add the following scopes:
| API | Scope | Purpose |
| --------------- | ---------------- | --------------------------------------------------------- |
| Microsoft Graph | `openid` | OpenID Connect authentication |
| Microsoft Graph | `offline_access` | Refresh tokens |
| Azure DevOps | `vso.code` | Read repositories, commits, pull requests, refs, branches |
| Azure DevOps | `vso.code_write` | Commit and push operations |
**Step 5: Prepare Azure DevOps**
1. In Azure DevOps, go to **Organization Settings > Security > Policies** and enable **Third-party application access via OAuth**.
2. Go to **Organization Settings > General** and connect your Microsoft Entra ID tenant.
**Step 6: Connect in Ona**
1. Go to **Settings → Runners** and select the runner you want to configure.
2. In the **Configure repository access** section, click **Select** next to **Azure DevOps (Entra ID)**. If other providers are already configured, click **Add a new provider** first.
3. Toggle **Enable OAuth**.
4. Enter the **Issuer URL**, **Client ID**, and **Client Secret** from the steps above. The client secret is encrypted with the runner's public key, so only the runner can read it.
5. Click **Save & Test**. This also verifies the connection to Entra ID.
#### Using Personal Access Tokens (PATs)
1. Go to **Settings → Runners** and select the runner you want to configure.
2. In the **Configure repository access** section, click **Select** next to **Azure DevOps**. If other providers are already configured, click **Add a new provider** first.
3. Toggle **Enable Personal Access Token**.
4. Click **Save**.
## Authorizing Azure DevOps Access
### Using OAuth (Microsoft Entra ID)
1. When creating your first environment, you will be prompted to authorize. Click **Connect**. A new window opens directing you to Microsoft Entra ID to authorize the OAuth app with the scopes configured above.
2. After authorizing, close the window. You should see a confirmation that Azure DevOps (Entra ID) is connected.
### Using Personal Access Tokens (PATs)
1. When creating your first environment, you will be asked to authorize the new application. Select *Provide a Personal Access Token*.
* Follow the instructions of the Azure documentation to create a PAT
* The name of the token and all required scopes are pre-set.
* By default, the token is valid for 30 days, but you can change the duration if needed.
2. After creating the token, return to the dialog and paste the token.
3. The environment will now be created using the provided token.
# Bitbucket Cloud
Source: https://ona.com/docs/ona/source-control/bitbucket
Configure Bitbucket Cloud as a source control provider for your Ona environments.
Source control integrations can be configured for both [Self-Hosted Runners](/docs/ona/runners/aws/overview) and [Ona Cloud](/docs/ona/runners/ona-cloud). You can set up a Bitbucket integration during runner creation or in the runner settings. Self-hosted Bitbucket instances (Bitbucket Server / Data Center) are currently not supported.
## Configuring Bitbucket Access
If Bitbucket is already set up on your runner, skip to [Authorizing Bitbucket Access](#authorizing-bitbucket-access).
### Ona Cloud
[Ona Cloud](/docs/ona/runners/ona-cloud) provides built-in Bitbucket Cloud integration with no configuration required.
[Authorize access to Bitbucket](#authorizing-bitbucket-access) when creating your first environment.
### Self-Hosted Runners
For self-hosted runners (like AWS), Bitbucket integration is configured during runner creation or in the runner settings.
We are currently supporting OAuth for authorizing Bitbucket access. Support for Personal Access Tokens (PATs) is planned.
#### Using OAuth
1. Go to **Settings → Runners** and select the runner you want to configure.
2. In the **Configure repository access** section, click **Select** next to **Bitbucket**. If other providers are already configured, click **Add a new provider** first.
3. Toggle **Enable OAuth**.
4. Follow the instructions in [Bitbucket's docs](https://support.atlassian.com/bitbucket-cloud/docs/use-oauth-on-bitbucket-cloud/) to create an OAuth app.
* The app name can be any name you like
* You can get the callback URL from the configuration dialog
* Select the required scopes:
* *account* so that the git author name and email can be set in the environment
* *repository* so that the repository can be cloned and the context URL can be parsed
* *repository:write* so that changes can be pushed from the environment
* *pullrequest* so that an environment can be started from a pull request
5. Enter the **Client ID** and **Client Secret** from the OAuth app. Bitbucket calls these *Key* and *Secret*. The client secret is encrypted with the runner's public key, so only the runner can read it.
6. Click **Save & Test**.
## Authorizing Bitbucket Access
### Using OAuth
1. When creating your first environment, you will be asked to authorize the new application. To use OAuth press the *Connect* button. A new window will open that directs you to Bitbucket to authorize the OAuth app. The requested scopes are *account*, *repository*, *repository:write*, and *pullrequest*.
* The *account* scope is required so that the git author name and email can be set in the environment
* The *repository* scope is required so that the repository can be cloned and the context URL can be parsed
* The *repository:write* scope is required so that changes can be pushed from the environment
* The *pullrequest* scope is required so that an environment can be started from a pull request
2. After you have authorized, you can close the window. After a few seconds you should get a confirmation that Bitbucket is now connected.
# GitHub
Source: https://ona.com/docs/ona/source-control/github
Configure GitHub as a source control provider for your Ona environments.
Source control integrations can be configured for both [Self-Hosted Runners](/docs/ona/runners/aws/overview) and [Ona Cloud](/docs/ona/runners/ona-cloud). You can set up a GitHub integration during runner creation or in the runner settings. Self-hosted GitHub instances are supported by changing the Host during setup.
## Configuring GitHub Access
If GitHub is already set up on your runner, skip to [Authorizing GitHub Access](#authorizing-github-access).
### Self-Hosted Runners
For self-hosted runners (like AWS), GitHub integration is configured during runner creation or in the runner settings.
There are two ways to integrate with GitHub. Both can be used simultaneously:
1. **OAuth App (Recommended):** Using an OAuth app allows users to sign in more quickly. You'll need to set up an OAuth app within Ona.
2. **Personal Access Token (PAT):** Each user will need to create a Personal Access Token. They will be provided with a deep link to do so on their first environment creation.
#### Using OAuth
1. Go to **Settings → Runners** and select the runner you want to configure.
2. In the **Configure repository access** section, click **Select** next to **GitHub**. If other providers are already configured, click **Add a new provider** first.
3. Toggle **Enable OAuth**.
4. Follow the instructions in [GitHub's docs](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) to create an OAuth app.
* The app name can be any name you like
* For the homepage URL, you can use [https://app.ona.com/](https://app.ona.com/)
* You can get the callback URL from the configuration dialog
5. Enter the **Client ID** and **Client Secret** from the OAuth app. The client secret is encrypted with the runner's public key, so only the runner can read it.
6. Click **Save & Test**.
#### Using Personal Access Tokens (PATs)
1. Go to **Settings → Runners** and select the runner you want to configure.
2. In the **Configure repository access** section, click **Select** next to **GitHub**. If other providers are already configured, click **Add a new provider** first.
3. Toggle **Enable Personal Access Token**.
4. Click **Save**.
### Ona Cloud
Ona Cloud provides built-in GitHub integration with no configuration required:
* **github.com** is supported by default using Ona's managed OAuth application
* **No OAuth app setup needed** - Ona manages the OAuth application for you
* **Automatic authentication** - Users can authenticate with their GitHub accounts immediately
For custom GitHub instances or advanced repository access configurations, consider [upgrading to Enterprise](/docs/ona/runners/ona-cloud#upgrading-to-enterprise) with self-hosted runners.
## Authorizing GitHub Access
### Using OAuth
1. When creating your first environment, you will be asked to authorize the new application. A new window will open that directs you to GitHub to authorize the OAuth app.
* The requested scopes are *repo*, *read:user*, *user:email*, and *workflow*.
* The *repo* permission is required so that your environment can clone the repository.
* The *read:user* permission is required so that the git author name can be set in the environment.
* The *user:email* permission is required so that the git author email can be set in the environment.
* The *workflow* permission is required so that GitHub Action YAML files can be edited in the environment.
2. After you have authorized, you can close the window and go back to the environment details screen.
### Using Personal Access Tokens (PATs)
1. The first time a user creates an environment, they will be asked to enter a Personal Access Token.
* Click the link provided on the screen to access the configuration dialog for creating a GitHub token.
* The name of the token and all required scopes are pre-set.
* By default, the token is valid for 30 days, but you can change the duration if needed.
2. After creating the token, return to the dialog and paste the token.
3. The environment will now be created using the provided token.
## Granting Access to Additional GitHub Organizations
After your initial OAuth authorization, you may need to grant Ona access to additional GitHub organizations to work with repositories from those organizations. This is a common scenario when you join new organizations or when organizations are added to your GitHub account after your initial setup.
This section applies to OAuth-based authentication. If you're using Personal Access Tokens (PATs), you'll need to ensure your token has access to the required organizations when creating the token.
### When You Need Additional Organization Access
You'll need to grant additional organization access when:
* You try to create an environment from a repository in an organization that wasn't previously authorized
* You receive an error message indicating insufficient permissions for a specific organization
* You join a new GitHub organization and want to use Ona with repositories from that organization
### Granting Access via GitHub Settings
To grant Ona access to additional GitHub organizations:
1. **Navigate to GitHub OAuth Applications:**
* Go to [GitHub Settings > Applications](https://github.com/settings/applications)
* Click on the **Authorized OAuth Apps** tab
* Find the Ona Cloud application in the list
2. **Review Current Organization Access:**
* Click on the Ona Cloud application to view its details
* You'll see a list of organizations and their access status
* Organizations may show as **Granted**, **Denied**, or **Request access**
3. **Grant Access to New Organizations:**
* For organizations showing **Request access**, click the **Request** button
* For organizations you own, access will be granted immediately
* For organizations you don't own, an access request will be sent to the organization owners
4. **Organization Owner Approval (if required):**
* If you're not an owner of the organization, the organization owners will receive a notification
* They can approve or deny the request from their organization settings
* You'll receive an email notification once the request is processed
## Custom Git email address
If you use GitHub's private email feature or want a specific commit email, create two user-level [environment variable secrets](/docs/ona/configuration/secrets/environment-variables):
* `GIT_COMMITTER_EMAIL` - your desired email
* `GIT_AUTHOR_EMAIL` - your desired email
These override the default Git configuration in all new environments. Existing environments are not affected. Create a new environment to apply the change.
## Repository access permissions
Ona requests broad GitHub permissions to enable environment creation from any of your repositories. Granting repository access does not mean AI agents automatically access your code. Agents only interact with repositories you explicitly open in an environment. Scoped repository access (granting access to specific repos only) is on the roadmap.
## Troubleshooting
* Verify you have access to the repository on GitHub directly
* Check that the organization has granted access to the Ona OAuth application
* Ensure you're a member of the organization with appropriate repository permissions
* Confirm you're a member of the organization on GitHub
* Check if the organization has restricted OAuth app access
* Contact your organization administrator to enable third-party application access
Contact your GitHub organization owners and ask them to review pending OAuth application requests in **Settings > Third-party access**.
If you enter a PAT, it confirms, then prompts again, the token is missing required scopes. Create a new token with `repo`, `workflow`, `read:user`, and `user:email`.
Generate a correctly scoped token at: [github.com/settings/tokens/new](https://github.com/settings/tokens/new?scopes=repo%2Cworkflow%2Cread%3Auser%2Cuser%3Aemail\&description=ona). The link in our UI during PAT setup also pre-fills the required scopes.
After creating the token, disconnect and reconnect GitHub at [Settings > Git Authentications](https://app.ona.com/settings/git-authentications).
1. Go to your organization's **Settings > Third-party access**
2. Review the Ona Cloud application request and verify the requested permissions
3. Click **Grant** or **Deny** based on your organization's policies
You can also pre-approve trusted applications in your organization's Third-party access settings.
# GitLab
Source: https://ona.com/docs/ona/source-control/gitlab
Configure GitLab as a source control provider for your Ona environments.
Source control integrations can be configured for both [Self-Hosted Runners](/docs/ona/runners/aws/overview) and [Ona Cloud](/docs/ona/runners/ona-cloud). You can set up a GitLab integration during runner creation or in the runner settings. Self-hosted GitLab instances are supported by changing the Host during setup.
## Configuring GitLab Access
If GitLab is already set up on your runner, skip to [Authorizing GitLab Access](#authorizing-gitlab-access).
### Self-Hosted Runners
For self-hosted runners (like AWS), GitLab integration is configured during runner creation or in the runner settings.
There are two ways to integrate with GitLab. Both can be used simultaneously:
1. **OAuth App (Recommended):** Using an OAuth app allows users to sign in more quickly. You'll need to set up an OAuth app within Ona.
2. **Personal Access Token (PAT):** Each user will need to create a Personal Access Token. They will be provided with a deep link to do so on their first environment creation.
#### Using OAuth
1. Go to **Settings → Runners** and select the runner you want to configure.
2. In the **Configure repository access** section, click **Select** next to **GitLab**. If other providers are already configured, click **Add a new provider** first.
3. Toggle **Enable OAuth**.
4. Follow the instructions in [GitLab's docs](https://docs.gitlab.com/ee/integration/oauth_provider.html) to create an OAuth app.
* The app name can be any name you like
* You can get the callback URL from the configuration dialog
* Select the required scopes:
* *api* so that the context URL can be parsed
* *read\_repository* so that your environment can clone the repository
* *read\_user* so that the git author name and email can be set in the environment
5. Enter the **Client ID** and **Client Secret** from the OAuth app. The client secret is encrypted with the runner's public key, so only the runner can read it.
6. Click **Save & Test**.
#### Using Personal Access Tokens (PATs)
1. Go to **Settings → Runners** and select the runner you want to configure.
2. In the **Configure repository access** section, click **Select** next to **GitLab**. If other providers are already configured, click **Add a new provider** first.
3. Toggle **Enable Personal Access Token**.
4. Click **Save**.
### Ona Cloud
Ona Cloud provides built-in GitLab integration with no configuration required:
* **gitlab.com** is supported by default using Ona's managed OAuth application
* **No OAuth app setup needed** - Ona manages the OAuth application for you
* **Automatic authentication** - Users can authenticate with their GitLab accounts immediately
For custom GitLab instances or advanced repository access configurations, consider [upgrading to Enterprise](/docs/ona/runners/ona-cloud#upgrading-to-enterprise) with self-hosted runners.
## Authorizing GitLab Access
### Using OAuth
1. When creating your first environment, you will be asked to authorize the new application. To use OAuth press the *Connect* button. A new window will open that directs you to GitLab to authorize the OAuth app. The requested scopes are *api*, *read\_repository* and *read\_user*.
* The *api* scope is required so that the context url can be parsed
* The *read\_repository* scope is required so that your environment can clone the repository
* The *read\_user scope* is required so that the git author name and git author email can be set in the environment
2. After you have authorized, you can close the window. After a few seconds you should get a confirmation that GitLab is now connected.
### Using Personal Access Tokens (PATs)
1. When creating your first environment, you will be asked to authorize the new application. Select *Provide a Personal Access Token*.
* Click the link provided on the screen to access the configuration dialog for creating a GitLab token.
* The name of the token and all required scopes are pre-set.
* By default, the token is valid for 30 days, but you can change the duration if needed.
2. After creating the token, return to the dialog and paste the token.
3. The environment will now be created using the provided token.
## Plan availability
| Plan | GitLab.com (SaaS) | Self-hosted GitLab |
| ---------- | ----------------- | ----------------------- |
| Core | ✓ | ✗ |
| Enterprise | ✓ | ✓ (self-hosted runners) |
GitLab login authentication on the Ona login page is currently in development. In the meantime, sign up with GitHub or Google, then add GitLab at [Settings > Git Authentications](https://app.ona.com/settings/git-authentications).
# Git providers
Source: https://ona.com/docs/ona/source-control/overview
Source control integrations in Ona
Ona connects to your existing Git provider to clone repositories into environments, push commits, and enable agents to interact with pull requests and issues. Source control integration is the bridge between your code host and Ona's [runner infrastructure](/docs/ona/runners/overview).
Ona's [two-plane architecture](/docs/ona/understanding/architecture) keeps source control credentials on runners. They never reach the management plane.
* **Your code stays where you choose.** With a self-hosted runner, source code and SCM credentials never leave your infrastructure. With [Ona Cloud](/docs/ona/runners/ona-cloud), code runs on Ona-managed infrastructure separate from the management plane.
* **Authentication is per-user.** Each developer authorizes their own access via OAuth or a Personal Access Token (PAT). Ona uses these credentials to clone repos and push changes on behalf of that user.
* **Agents inherit your permissions.** When an agent creates a pull request or adds a review comment, it acts using the environment owner's SCM credentials and respects the same repository permissions.
## How it works
Source control configuration happens at two levels:
1. **Runner level**: An administrator configures which Git providers and authentication methods (OAuth, PAT) are available on a runner. This determines what providers developers can connect to.
2. **User level**: Each developer authorizes access to their Git provider. On first environment creation, Ona prompts for authorization using the methods the administrator configured.
When a developer or agent starts an environment, the runner uses the developer's credentials to clone the repository. All subsequent git operations (commits, pushes, fetches) use the same credentials within that environment.
## Supported providers
| Provider | OAuth | PAT | Agent SCM tools |
| ------------------------------------------------ | ----- | ------- | ---------------- |
| [GitHub](/docs/ona/source-control/github) | Yes | Yes | Yes |
| [GitLab](/docs/ona/source-control/gitlab) | Yes | Yes | Yes |
| [Bitbucket Cloud](/docs/ona/source-control/bitbucket) | Yes | Planned | Yes (Cloud only) |
| [Azure DevOps](/docs/ona/source-control/azuredevops) | Yes | Yes | No |
[Agent SCM tools](/docs/ona/agents/scm-tools) let agents create pull requests, manage issues, and add code review comments directly through your provider's API.
### Organization controls for SCM tools
Administrators can control whether agents are allowed to use SCM tools across the organization. This is useful when your team requires human review of all SCM interactions, or when rolling out agent-assisted workflows gradually.
Configure this in [Settings > Agents > Policies](https://app.ona.com/settings/agent-policies). When SCM tools are disabled, agents can still clone, commit, and push code using git, but cannot interact with your provider's API to create PRs or manage issues. See [SCM tools policy](/docs/ona/organizations/policies/scm-tools) for details.
## Setting up Git authentication
To connect a Git provider to your Ona account:
1. Set up the SCM integration for your runner at [Settings > Runners](https://app.ona.com/settings/runners). **This is required for Enterprise only.**
2. Connect or disconnect available providers at [Settings > Git Authentications](https://app.ona.com/settings/git-authentications)
For provider-specific setup instructions including required scopes and OAuth app configuration, see the individual provider pages above.
## Troubleshooting
If you see `Failed to create provider - Aborted: operation cancelled` when configuring repository access, switch from Personal Access Token to **OAuth** authentication.
# API Reference
Source: https://ona.com/docs/api-reference
Call the public Ona Connect API from scripts, services, and generated clients.
The Ona API is a [Connect](https://connectrpc.com/) RPC API for managing Ona resources. Service and method pages are generated directly from the public Protocol Buffer definitions whenever the API is generated.
## Use the API base URL
Send requests to `https://app.ona.com/api`.
If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain. Create and use tokens from the same domain.
## Authenticate requests
Send a [personal access token](/docs/ona/integrations/personal-access-token) or [service account token](/docs/ona/organizations/service-accounts) as a Bearer token in the `Authorization` header.
```bash theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.EnvironmentService/ListEnvironments" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{}'
```
Tokens inherit the permissions of their user or service account. A request fails when the token does not grant the permission required by the method.
## Send Connect requests
Unary methods accept `POST` requests with Protocol Buffer JSON request bodies. The generated method pages list the route, RPC cardinality, request fields, response fields, validation constraints, and a copyable example.
Protocol Buffer JSON differs from ordinary JSON in a few places:
* Field names use their lower camel-case JSON name, such as `environmentId`.
* Enum values use symbolic names, such as `ENVIRONMENT_PHASE_RUNNING`.
* 64-bit integers are strings.
* `bytes` fields are base64-encoded strings.
* Timestamps use RFC 3339 strings and durations use strings such as `60s`.
* Unknown fields are rejected.
Server-streaming methods use Connect message envelopes with `application/connect+json` or `application/connect+proto`. Use a generated Connect client for streaming rather than sending an unframed JSON body directly.
## Handle errors
Connect errors contain a machine-readable code and message. Treat authentication and permission errors separately from validation failures, and do not retry requests with invalid arguments. Retry transient errors such as `unavailable` with exponential backoff.
Never log Bearer tokens or secret request fields when recording failed requests.
# Block Account
Source: https://ona.com/docs/api-reference/generated/account/block-account
Blocks an account, preventing all API access.
`Unary` · [`Accounts`](/docs/api-reference/generated/account/overview)
Blocks an account, preventing all API access.
Use this method to:
* Revoke access for policy violations
* Handle abuse cases
* Enforce compliance requirements
When an account is blocked:
* All API requests return 403 PERMISSION\_DENIED
* All running environments are stopped
* All active subscriptions are cancelled
Requires the `block_account` permission.
### Examples
* Block account for policy violation:
```yaml theme={null}
accountId: "f53d2330-3795-4c5d-a1f3-453121af9c60"
reason: "Terms of Service violation - spam"
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AccountService/BlockAccount
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AccountService/BlockAccount" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"accountId": "",
"reason": ""
}'
```
```python Python theme={null}
import gitpod.v1.account_pb2 as account_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = account_pb2.BlockAccountRequest(
account_id="",
reason="",
)
response = ona.services.account.block_account(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { BlockAccountRequestSchema } from "@gitpod/sdk/gitpod/v1/account_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(BlockAccountRequestSchema, {
accountId: "",
reason: "",
});
const response = await ona.services.account.blockAccount(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.BlockAccountRequest{
AccountId: "",
Reason: "",
})
response, err := ona.Services.Account.BlockAccount(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"accountId": "",
"reason": ""
}
```
## Request
`gitpod.v1.BlockAccountRequest`
| Field | Type | Required | Description |
| ----------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `accountId` | string | Yes | account\_id is the UUID of the account to block Constraints: `required=true, string.uuid=true`. |
| `reason` | string | Yes | reason is the reason for blocking the account (required for audit trail) Constraints: `required=true, string.max_len=1024, string.min_len=1`. |
## Response
`gitpod.v1.BlockAccountResponse`
| Field | Type | Required | Description |
| ------------------------ | ------- | -------- | --------------------------------------------------------------------------- |
| `environmentsStopped` | integer | No | environments\_stopped is the number of environments that were stopped |
| `subscriptionsCancelled` | integer | No | subscriptions\_cancelled is the number of subscriptions that were cancelled |
# Delete Account
Source: https://ona.com/docs/api-reference/generated/account/delete-account
Deletes an account permanently.
`Unary` · [`Accounts`](/docs/api-reference/generated/account/overview)
Deletes an account permanently.
Use this method to:
* Remove unused accounts
* Clean up test accounts
* Complete account deletion requests
The account must not be an active member of any organization.
### Examples
* Delete account:
Permanently removes an account.
```yaml theme={null}
accountId: "f53d2330-3795-4c5d-a1f3-453121af9c60"
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AccountService/DeleteAccount
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AccountService/DeleteAccount" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"accountId": ""
}'
```
```python Python theme={null}
import gitpod.v1.account_pb2 as account_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = account_pb2.DeleteAccountRequest(
account_id="",
)
response = ona.services.account.delete_account(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { DeleteAccountRequestSchema } from "@gitpod/sdk/gitpod/v1/account_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(DeleteAccountRequestSchema, {
accountId: "",
});
const response = await ona.services.account.deleteAccount(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.DeleteAccountRequest{
AccountId: "",
})
response, err := ona.Services.Account.DeleteAccount(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"accountId": ""
}
```
## Request
`gitpod.v1.DeleteAccountRequest`
| Field | Type | Required | Description |
| ----------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------ |
| `accountId` | string | Yes | Constraints: `required=true, string.uuid=true`. |
| `reason` | string | No | reason is an optional field for the reason for account deletion Constraints: `ignore=1, string.max_len=256`. |
## Response
`gitpod.v1.DeleteAccountResponse`
This message has no fields.
# Get Account
Source: https://ona.com/docs/api-reference/generated/account/get-account
Gets information about the currently authenticated account.
`Unary` · [`Accounts`](/docs/api-reference/generated/account/overview)
Gets information about the currently authenticated account.
Use this method to:
* Retrieve account profile information
* Check organization memberships
* View account settings
* Get joinable organizations
### Examples
* Get account details:
Retrieves information about the authenticated account.
```yaml theme={null}
{}
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AccountService/GetAccount
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AccountService/GetAccount" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{}'
```
```python Python theme={null}
import gitpod.v1.account_pb2 as account_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = account_pb2.GetAccountRequest()
response = ona.services.account.get_account(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { GetAccountRequestSchema } from "@gitpod/sdk/gitpod/v1/account_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(GetAccountRequestSchema, {});
const response = await ona.services.account.getAccount(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.GetAccountRequest{})
response, err := ona.Services.Account.GetAccount(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{}
```
## Request
`gitpod.v1.GetAccountRequest`
This message has no fields.
## Response
`gitpod.v1.GetAccountResponse`
| Field | Type | Required | Description |
| --------- | ---------------------------------- | -------- | ----------------------------- |
| `account` | [Account](#type-gitpod-v1-account) | Yes | Constraints: `required=true`. |
## Related types
`gitpod.v1.Account`
| Field | Type | Required | Description |
| --------------------- | ---------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------- |
| `id` | string | Yes | Constraints: `required=true, string.uuid=true`. |
| `name` | string | Yes | Constraints: `required=true`. |
| `avatarUrl` | string | No | |
| `email` | string | Yes | Constraints: `required=true`. |
| `createdAt` | RFC 3339 timestamp | Yes | Constraints: `required=true`. |
| `updatedAt` | RFC 3339 timestamp | Yes | Constraints: `required=true`. |
| `memberships` | array of [AccountMembership](#type-gitpod-v1-account-membership) | No | |
| `joinables` | array of [JoinableOrganization](#type-gitpod-v1-joinable-organization) | No | **Deprecated.** joinables is deprecated. Use ListJoinableOrganizations instead. |
| `publicEmailProvider` | boolean | No | public\_email\_provider is true if the email for the Account matches a known public email provider |
| `organizationId` | string | No | organization\_id is the ID of the organization the account is owned by if it's created through custom SSO |
`gitpod.v1.AccountMembership`
| Field | Type | Required | Description |
| ------------------------- | ----------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `userId` | string | Yes | user\_id is the ID the user has in the organization Constraints: `required=true, string.uuid=true`. |
| `userRole` | [OrganizationRole](#enum-gitpod-v1-organization-role) | Yes | user\_role is the role the user has in the organization Constraints: `required=true`. |
| `organizationId` | string | Yes | organization\_id is the id of the organization the user is a member of Constraints: `required=true, string.uuid=true`. |
| `organizationName` | string | Yes | organization\_name is the name of the organization the user is a member of Constraints: `required=true`. |
| `organizationMemberCount` | integer | No | organization\_member\_count is the member count of the organization the user is a member of |
| `organizationTier` | [OrganizationTier](#enum-gitpod-v1-organization-tier) | No | organization\_tier is the tier of the organization (Free, Core, Enterprise) |
`gitpod.v1.JoinableOrganization`
| Field | Type | Required | Description |
| ------------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------- |
| `organizationId` | string | Yes | organization\_id is the id of the organization the user can join Constraints: `required=true, string.uuid=true`. |
| `organizationName` | string | Yes | organization\_name is the name of the organization the user can join Constraints: `required=true`. |
| `organizationMemberCount` | integer | No | organization\_member\_count is the member count of the organization the user can join |
| Value | Number | Description |
| ------------------------------- | -----: | ----------- |
| `ORGANIZATION_ROLE_UNSPECIFIED` | 0 | |
| `ORGANIZATION_ROLE_ADMIN` | 1 | |
| `ORGANIZATION_ROLE_MEMBER` | 2 | |
| Value | Number | Description |
| ------------------------------- | -----: | ----------- |
| `ORGANIZATION_TIER_UNSPECIFIED` | 0 | |
| `ORGANIZATION_TIER_FREE` | 1 | |
| `ORGANIZATION_TIER_ENTERPRISE` | 2 | |
| `ORGANIZATION_TIER_CORE` | 3 | |
| `ORGANIZATION_TIER_FREE_ONA` | 4 | |
# Get SSO Login URL
Source: https://ona.com/docs/api-reference/generated/account/get-sso-login-url
Gets the SSO login URL for a specific email domain.
`Unary` · [`Accounts`](/docs/api-reference/generated/account/overview)
Gets the SSO login URL for a specific email domain.
Use this method to:
* Initiate SSO authentication
* Get organization-specific login URLs
* Handle SSO redirects
### Examples
* Get login URL:
Retrieves SSO URL for email domain.
```yaml theme={null}
email: "user@company.com"
```
* Get URL with return path:
Gets SSO URL with specific return location.
```yaml theme={null}
email: "user@company.com"
returnTo: "https://gitpod.io/workspaces"
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AccountService/GetSSOLoginURL
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AccountService/GetSSOLoginURL" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"email": ""
}'
```
```python Python theme={null}
import gitpod.v1.account_pb2 as account_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = account_pb2.GetSSOLoginURLRequest(
email="",
)
response = ona.services.account.get_sso_login_url(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { GetSSOLoginURLRequestSchema } from "@gitpod/sdk/gitpod/v1/account_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(GetSSOLoginURLRequestSchema, {
email: "",
});
const response = await ona.services.account.getSSOLoginURL(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.GetSSOLoginURLRequest{
Email: "",
})
response, err := ona.Services.Account.GetSSOLoginURL(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"email": ""
}
```
## Request
`gitpod.v1.GetSSOLoginURLRequest`
| Field | Type | Required | Description |
| ---------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------- |
| `email` | string | Yes | email is the email the user wants to login with Constraints: `required=true, string.email=true`. |
| `returnTo` | string | No | return\_to is the URL the user will be redirected to after login Constraints: `ignore=1, string.uri=true`. |
## Response
`gitpod.v1.GetSSOLoginURLResponse`
| Field | Type | Required | Description |
| ---------- | ------ | -------- | ----------------------------------------------------------------------------------------- |
| `loginUrl` | string | Yes | login\_url is the URL to redirect the user to for SSO login Constraints: `required=true`. |
# List Joinable Organizations
Source: https://ona.com/docs/api-reference/generated/account/list-joinable-organizations
Lists organizations that the currently authenticated account can join.
`Unary` · [`Accounts`](/docs/api-reference/generated/account/overview)
Lists organizations that the currently authenticated account can join.
Use this method to:
* Discover organizations associated with the account's email domain.
* Allow users to join existing organizations.
* Display potential organizations during onboarding.
### Examples
* List joinable organizations:
Retrieves a list of organizations the account can join.
```yaml theme={null}
{}
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AccountService/ListJoinableOrganizations
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AccountService/ListJoinableOrganizations" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"pagination": {
"pageSize": 1
}
}'
```
```python Python theme={null}
import gitpod.v1.account_pb2 as account_pb2
import gitpod.v1.pagination_pb2 as pagination_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = account_pb2.ListJoinableOrganizationsRequest(
pagination=pagination_pb2.PaginationRequest(
page_size=1,
),
)
response = ona.services.account.list_joinable_organizations(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { ListJoinableOrganizationsRequestSchema } from "@gitpod/sdk/gitpod/v1/account_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(ListJoinableOrganizationsRequestSchema, {
pagination: {
pageSize: 1,
},
});
const response = await ona.services.account.listJoinableOrganizations(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.ListJoinableOrganizationsRequest{
Pagination: &gitpodpb.PaginationRequest{
PageSize: 1,
},
})
response, err := ona.Services.Account.ListJoinableOrganizations(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"pagination": {
"pageSize": 1
}
}
```
## Request
`gitpod.v1.ListJoinableOrganizationsRequest`
| Field | Type | Required | Description |
| ------------ | ------------------------------------------------------- | -------- | ----------------------------------------------------------------------------- |
| `pagination` | [PaginationRequest](#type-gitpod-v1-pagination-request) | No | pagination contains the pagination options for listing joinable organizations |
## Response
`gitpod.v1.ListJoinableOrganizationsResponse`
| Field | Type | Required | Description |
| ----------------------- | ---------------------------------------------------------------------- | -------- | ----------------------------- |
| `joinableOrganizations` | array of [JoinableOrganization](#type-gitpod-v1-joinable-organization) | No | |
| `pagination` | [PaginationResponse](#type-gitpod-v1-pagination-response) | Yes | Constraints: `required=true`. |
## Related types
`gitpod.v1.JoinableOrganization`
| Field | Type | Required | Description |
| ------------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------- |
| `organizationId` | string | Yes | organization\_id is the id of the organization the user can join Constraints: `required=true, string.uuid=true`. |
| `organizationName` | string | Yes | organization\_name is the name of the organization the user can join Constraints: `required=true`. |
| `organizationMemberCount` | integer | No | organization\_member\_count is the member count of the organization the user can join |
`gitpod.v1.PaginationRequest`
| Field | Type | Required | Description |
| ---------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `pageSize` | integer | No | Page size is the maximum number of results to retrieve per page. Defaults to 25. Maximum 100. Constraints: `int32.gte=0, int32.lte=100`. |
| `token` | string | No | Token for the next set of results that was returned as next\_token of a PaginationResponse |
`gitpod.v1.PaginationResponse`
| Field | Type | Required | Description |
| ----------- | ------ | -------- | --------------------------------------------------------------------------------------- |
| `nextToken` | string | No | Token passed for retrieving the next set of results. Empty if there are no more results |
# List Login Providers
Source: https://ona.com/docs/api-reference/generated/account/list-login-providers
Lists available login providers with optional filtering.
`Unary` · [`Accounts`](/docs/api-reference/generated/account/overview)
Lists available login providers with optional filtering.
Use this method to:
* View supported authentication methods
* Get provider-specific login URLs
* Filter providers by invite
### Examples
* List all providers:
Shows all available login providers.
```yaml theme={null}
pagination:
pageSize: 20
```
* List for specific invite:
Shows providers available for an invite.
```yaml theme={null}
filter:
inviteId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
pagination:
pageSize: 20
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AccountService/ListLoginProviders
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AccountService/ListLoginProviders" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"pagination": {
"pageSize": 1
}
}'
```
```python Python theme={null}
import gitpod.v1.account_pb2 as account_pb2
import gitpod.v1.pagination_pb2 as pagination_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = account_pb2.ListLoginProvidersRequest(
pagination=pagination_pb2.PaginationRequest(
page_size=1,
),
)
response = ona.services.account.list_login_providers(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { ListLoginProvidersRequestSchema } from "@gitpod/sdk/gitpod/v1/account_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(ListLoginProvidersRequestSchema, {
pagination: {
pageSize: 1,
},
});
const response = await ona.services.account.listLoginProviders(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.ListLoginProvidersRequest{
Pagination: &gitpodpb.PaginationRequest{
PageSize: 1,
},
})
response, err := ona.Services.Account.ListLoginProviders(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"pagination": {
"pageSize": 1
}
}
```
## Request
`gitpod.v1.ListLoginProvidersRequest`
| Field | Type | Required | Description |
| ------------ | ------------------------------------------------------------- | -------- | -------------------------------------------------------------------- |
| `pagination` | [PaginationRequest](#type-gitpod-v1-pagination-request) | No | pagination contains the pagination options for listing login methods |
| `filter` | [Filter](#type-gitpod-v1-list-login-providers-request-filter) | No | filter contains the filter options for listing login methods |
## Response
`gitpod.v1.ListLoginProvidersResponse`
| Field | Type | Required | Description |
| ---------------- | --------------------------------------------------------- | -------- | --------------------------------------------------------------------- |
| `pagination` | [PaginationResponse](#type-gitpod-v1-pagination-response) | Yes | Constraints: `required=true`. |
| `loginProviders` | array of [LoginProvider](#type-gitpod-v1-login-provider) | No | |
| `allowCustom` | boolean | No | allow\_custom indicates whether custom SSO is allowed for this domain |
## Related types
`gitpod.v1.ListLoginProvidersRequest.Filter`
| Field | Type | Required | Description |
| ---------- | ------ | -------- | ---------------------------------------------------------------------------------------------------- |
| `inviteId` | string | No | invite\_id is the ID of the invite URL the user wants to login with Constraints: `string.uuid=true`. |
| `email` | string | No | email is the email address to filter SSO providers by |
`gitpod.v1.LoginProvider`
| Field | Type | Required | Description |
| ---------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------- |
| `loginUrl` | string | No | login\_url is the URL to redirect the browser agent to for login, when provider is "custom" |
| `provider` | string | Yes | provider is the provider used by this login method, e.g. "github", "google", "custom" Constraints: `required=true`. |
`gitpod.v1.PaginationRequest`
| Field | Type | Required | Description |
| ---------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `pageSize` | integer | No | Page size is the maximum number of results to retrieve per page. Defaults to 25. Maximum 100. Constraints: `int32.gte=0, int32.lte=100`. |
| `token` | string | No | Token for the next set of results that was returned as next\_token of a PaginationResponse |
`gitpod.v1.PaginationResponse`
| Field | Type | Required | Description |
| ----------- | ------ | -------- | --------------------------------------------------------------------------------------- |
| `nextToken` | string | No | Token passed for retrieving the next set of results. Empty if there are no more results |
# List SSO Logins
Source: https://ona.com/docs/api-reference/generated/account/list-sso-logins
Call gitpod.v1.AccountService.ListSSOLogins.
`Unary` · [`Accounts`](/docs/api-reference/generated/account/overview)
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AccountService/ListSSOLogins
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AccountService/ListSSOLogins" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"email": ""
}'
```
```python Python theme={null}
import gitpod.v1.account_pb2 as account_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = account_pb2.ListSSOLoginsRequest(
email="",
)
response = ona.services.account.list_sso_logins(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { ListSSOLoginsRequestSchema } from "@gitpod/sdk/gitpod/v1/account_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(ListSSOLoginsRequestSchema, {
email: "",
});
const response = await ona.services.account.listSSOLogins(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.ListSSOLoginsRequest{
Email: "",
})
response, err := ona.Services.Account.ListSSOLogins(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"email": ""
}
```
## Request
`gitpod.v1.ListSSOLoginsRequest`
| Field | Type | Required | Description |
| ------------ | ------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------- |
| `email` | string | Yes | email is the email the user wants to login with Constraints: `required=true, string.email=true`. |
| `returnTo` | string | No | return\_to is the URL the user will be redirected to after login Constraints: `ignore=1, string.uri=true`. |
| `pagination` | [PaginationRequest](#type-gitpod-v1-pagination-request) | No | pagination contains the pagination options for listing SSO logins |
## Response
`gitpod.v1.ListSSOLoginsResponse`
| Field | Type | Required | Description |
| ------------ | ---------------------------------------------------------------- | -------- | ----------------------------- |
| `logins` | array of [Login](#type-gitpod-v1-list-sso-logins-response-login) | No | |
| `pagination` | [PaginationResponse](#type-gitpod-v1-pagination-response) | Yes | Constraints: `required=true`. |
## Related types
`gitpod.v1.ListSSOLoginsResponse.Login`
| Field | Type | Required | Description |
| ------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------- |
| `displayName` | string | Yes | provider is the provider used by this login method, e.g. "github", "google", "custom" Constraints: `required=true`. |
| `loginUrl` | string | Yes | login\_url is the URL to redirect the user to for SSO login Constraints: `required=true`. |
`gitpod.v1.PaginationRequest`
| Field | Type | Required | Description |
| ---------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `pageSize` | integer | No | Page size is the maximum number of results to retrieve per page. Defaults to 25. Maximum 100. Constraints: `int32.gte=0, int32.lte=100`. |
| `token` | string | No | Token for the next set of results that was returned as next\_token of a PaginationResponse |
`gitpod.v1.PaginationResponse`
| Field | Type | Required | Description |
| ----------- | ------ | -------- | --------------------------------------------------------------------------------------- |
| `nextToken` | string | No | Token passed for retrieving the next set of results. Empty if there are no more results |
# Accounts
Source: https://ona.com/docs/api-reference/generated/account/overview
Reference for the Accounts API methods.
## Methods
Blocks an account, preventing all API access.
Deletes an account permanently.
Gets information about the currently authenticated account.
Gets the SSO login URL for a specific email domain.
Lists organizations that the currently authenticated account can join.
Lists available login providers with optional filtering.
Call gitpod.v1.AccountService.ListSSOLogins.
Unblocks a previously blocked account, restoring API access.
# Unblock Account
Source: https://ona.com/docs/api-reference/generated/account/unblock-account
Unblocks a previously blocked account, restoring API access.
`Unary` · [`Accounts`](/docs/api-reference/generated/account/overview)
Unblocks a previously blocked account, restoring API access.
Use this method to:
* Restore access after resolving policy violations
* Reinstate accounts after review
Note: Unblocking does NOT restore:
* Stopped environments (must be restarted manually)
* Cancelled subscriptions (must be re-subscribed)
* Deleted resources
Requires the `block_account` permission.
### Examples
* Unblock account:
```yaml theme={null}
accountId: "f53d2330-3795-4c5d-a1f3-453121af9c60"
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AccountService/UnblockAccount
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AccountService/UnblockAccount" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"accountId": ""
}'
```
```python Python theme={null}
import gitpod.v1.account_pb2 as account_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = account_pb2.UnblockAccountRequest(
account_id="",
)
response = ona.services.account.unblock_account(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { UnblockAccountRequestSchema } from "@gitpod/sdk/gitpod/v1/account_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(UnblockAccountRequestSchema, {
accountId: "",
});
const response = await ona.services.account.unblockAccount(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.UnblockAccountRequest{
AccountId: "",
})
response, err := ona.Services.Account.UnblockAccount(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"accountId": ""
}
```
## Request
`gitpod.v1.UnblockAccountRequest`
| Field | Type | Required | Description |
| ----------- | ------ | -------- | ------------------------------------------------------------------------------------------------- |
| `accountId` | string | Yes | account\_id is the UUID of the account to unblock Constraints: `required=true, string.uuid=true`. |
## Response
`gitpod.v1.UnblockAccountResponse`
This message has no fields.
# Create Agent Execution Conversation Token
Source: https://ona.com/docs/api-reference/generated/agent/create-agent-execution-conversation-token
Creates a token for conversation access with a specific agent run.
`Unary` · [`Agents`](/docs/api-reference/generated/agent/overview)
Creates a token for conversation access with a specific agent run.
This method generates a temporary token that can be used to securely
connect to an ongoing agent conversation, for example in a web UI.
### Examples
* Create a token to join an agent run conversation in a front-end application:
```yaml theme={null}
agentExecutionId: "6fa1a3c7-fbb7-49d1-ba56-1890dc7c4c35"
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AgentService/CreateAgentExecutionConversationToken
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AgentService/CreateAgentExecutionConversationToken" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"agentExecutionId": ""
}'
```
```python Python theme={null}
import gitpod.v1.agent_pb2 as agent_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = agent_pb2.CreateAgentExecutionConversationTokenRequest(
agent_execution_id="",
)
response = ona.services.agent.create_agent_execution_conversation_token(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { CreateAgentExecutionConversationTokenRequestSchema } from "@gitpod/sdk/gitpod/v1/agent_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(CreateAgentExecutionConversationTokenRequestSchema, {
agentExecutionId: "",
});
const response = await ona.services.agent.createAgentExecutionConversationToken(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.CreateAgentExecutionConversationTokenRequest{
AgentExecutionId: "",
})
response, err := ona.Services.Agent.CreateAgentExecutionConversationToken(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"agentExecutionId": ""
}
```
## Request
`gitpod.v1.CreateAgentExecutionConversationTokenRequest`
| Field | Type | Required | Description |
| ------------------ | ------ | -------- | -------------------------------- |
| `agentExecutionId` | string | No | Constraints: `string.uuid=true`. |
## Response
`gitpod.v1.CreateAgentExecutionConversationTokenResponse`
| Field | Type | Required | Description |
| ------- | ------ | -------- | ----------- |
| `token` | string | No | |
# Create Prompt
Source: https://ona.com/docs/api-reference/generated/agent/create-prompt
Creates a new prompt.
`Unary` · [`Agents`](/docs/api-reference/generated/agent/overview)
Creates a new prompt.
Use this method to:
* Define new prompts for templates or commands
* Set up organization-wide prompt libraries
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AgentService/CreatePrompt
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AgentService/CreatePrompt" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"name": ""
}'
```
```python Python theme={null}
import gitpod.v1.agent_pb2 as agent_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = agent_pb2.CreatePromptRequest(
name="",
)
response = ona.services.agent.create_prompt(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { CreatePromptRequestSchema } from "@gitpod/sdk/gitpod/v1/agent_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(CreatePromptRequestSchema, {
name: "",
});
const response = await ona.services.agent.createPrompt(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.CreatePromptRequest{
Name: "",
})
response, err := ona.Services.Agent.CreatePrompt(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"name": ""
}
```
## Request
`gitpod.v1.CreatePromptRequest`
| Field | Type | Required | Description |
| ------------- | ------- | -------- | ------------------------------------------------------------------ |
| `name` | string | No | Constraints: `string.max_len=255, string.min_len=1`. |
| `description` | string | No | Constraints: `string.max_len=500, string.min_len=1`. |
| `prompt` | string | No | Constraints: `string.max_len=20000, string.min_len=1`. |
| `isTemplate` | boolean | No | |
| `isCommand` | boolean | No | |
| `command` | string | No | Constraints: `string.max_len=50, string.pattern=^[a-zA-Z0-9_-]*$`. |
| `isSkill` | boolean | No | |
## Response
`gitpod.v1.CreatePromptResponse`
| Field | Type | Required | Description |
| -------- | -------------------------------- | -------- | ----------- |
| `prompt` | [Prompt](#type-gitpod-v1-prompt) | No | |
## Related types
`gitpod.v1.Prompt`
| Field | Type | Required | Description |
| ---------- | ------------------------------------------------- | -------- | ----------- |
| `id` | string | No | |
| `metadata` | [PromptMetadata](#type-gitpod-v1-prompt-metadata) | No | |
| `spec` | [PromptSpec](#type-gitpod-v1-prompt-spec) | No | |
`gitpod.v1.PromptMetadata`
| Field | Type | Required | Description |
| ---------------- | ------------------ | -------- | -------------------------------------------------------------------------------------------------------- |
| `organizationId` | string | No | organization\_id is the ID of the organization that contains the prompt Constraints: `string.uuid=true`. |
| `name` | string | No | name is the human readable name of the prompt |
| `description` | string | No | description is a description of what the prompt does |
| `creator` | Subject | No | creator is the identity of the prompt creator |
| `createdAt` | RFC 3339 timestamp | No | |
| `updatedAt` | RFC 3339 timestamp | No | |
`gitpod.v1.PromptSpec`
| Field | Type | Required | Description |
| ------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `prompt` | string | No | prompt is the content of the prompt Constraints: `string.max_len=20000`. |
| `isTemplate` | boolean | No | is\_template indicates if this prompt is a template |
| `isCommand` | boolean | No | is\_command indicates if this prompt is a command |
| `command` | string | No | command is the unique command string within the organization Constraints: `string.max_len=50, string.pattern=^[a-zA-Z0-9_-]*$`. |
| `isSkill` | boolean | No | is\_skill indicates if this prompt is a skill (workflow instructions for agents) |
# Delete Agent Execution
Source: https://ona.com/docs/api-reference/generated/agent/delete-agent-execution
Deletes an agent run.
`Unary` · [`Agents`](/docs/api-reference/generated/agent/overview)
Deletes an agent run.
Use this method to:
* Clean up agent runs that are no longer needed
### Examples
* Delete an agent run by ID:
```yaml theme={null}
agentExecutionId: "6fa1a3c7-fbb7-49d1-ba56-1890dc7c4c35"
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AgentService/DeleteAgentExecution
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AgentService/DeleteAgentExecution" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"agentExecutionId": ""
}'
```
```python Python theme={null}
import gitpod.v1.agent_pb2 as agent_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = agent_pb2.DeleteAgentExecutionRequest(
agent_execution_id="",
)
response = ona.services.agent.delete_agent_execution(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { DeleteAgentExecutionRequestSchema } from "@gitpod/sdk/gitpod/v1/agent_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(DeleteAgentExecutionRequestSchema, {
agentExecutionId: "",
});
const response = await ona.services.agent.deleteAgentExecution(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.DeleteAgentExecutionRequest{
AgentExecutionId: "",
})
response, err := ona.Services.Agent.DeleteAgentExecution(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"agentExecutionId": ""
}
```
## Request
`gitpod.v1.DeleteAgentExecutionRequest`
| Field | Type | Required | Description |
| ------------------ | ------ | -------- | -------------------------------- |
| `agentExecutionId` | string | No | Constraints: `string.uuid=true`. |
## Response
`gitpod.v1.DeleteAgentExecutionResponse`
This message has no fields.
# Delete Prompt
Source: https://ona.com/docs/api-reference/generated/agent/delete-prompt
Deletes a prompt.
`Unary` · [`Agents`](/docs/api-reference/generated/agent/overview)
Deletes a prompt.
Use this method to:
* Remove unused prompts
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AgentService/DeletePrompt
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AgentService/DeletePrompt" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"promptId": ""
}'
```
```python Python theme={null}
import gitpod.v1.agent_pb2 as agent_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = agent_pb2.DeletePromptRequest(
prompt_id="",
)
response = ona.services.agent.delete_prompt(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { DeletePromptRequestSchema } from "@gitpod/sdk/gitpod/v1/agent_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(DeletePromptRequestSchema, {
promptId: "",
});
const response = await ona.services.agent.deletePrompt(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.DeletePromptRequest{
PromptId: "",
})
response, err := ona.Services.Agent.DeletePrompt(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"promptId": ""
}
```
## Request
`gitpod.v1.DeletePromptRequest`
| Field | Type | Required | Description |
| ---------- | ------ | -------- | -------------------------------- |
| `promptId` | string | No | Constraints: `string.uuid=true`. |
## Response
`gitpod.v1.DeletePromptResponse`
This message has no fields.
# Get Agent Execution
Source: https://ona.com/docs/api-reference/generated/agent/get-agent-execution
Gets details about a specific agent run, including its metadata, specification,
`Unary` · [`Agents`](/docs/api-reference/generated/agent/overview)
Gets details about a specific agent run, including its metadata, specification,
and status (phase, error messages, and usage statistics).
Use this method to:
* Monitor the run's progress
* Retrieve the agent's conversation URL
* Check if an agent run is actively producing output
### Examples
* Get agent run details by ID:
```yaml theme={null}
agentExecutionId: "6fa1a3c7-fbb7-49d1-ba56-1890dc7c4c35"
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AgentService/GetAgentExecution
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AgentService/GetAgentExecution" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"agentExecutionId": ""
}'
```
```python Python theme={null}
import gitpod.v1.agent_pb2 as agent_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = agent_pb2.GetAgentExecutionRequest(
agent_execution_id="",
)
response = ona.services.agent.get_agent_execution(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { GetAgentExecutionRequestSchema } from "@gitpod/sdk/gitpod/v1/agent_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(GetAgentExecutionRequestSchema, {
agentExecutionId: "",
});
const response = await ona.services.agent.getAgentExecution(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.GetAgentExecutionRequest{
AgentExecutionId: "",
})
response, err := ona.Services.Agent.GetAgentExecution(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"agentExecutionId": ""
}
```
## Request
`gitpod.v1.GetAgentExecutionRequest`
| Field | Type | Required | Description |
| ------------------ | ------ | -------- | -------------------------------- |
| `agentExecutionId` | string | No | Constraints: `string.uuid=true`. |
## Response
`gitpod.v1.GetAgentExecutionResponse`
| Field | Type | Required | Description |
| ---------------- | ------------------------------------------------- | -------- | ----------- |
| `agentExecution` | [AgentExecution](#type-gitpod-v1-agent-execution) | No | |
## Related types
`gitpod.v1.AgentExecution`
| Field | Type | Required | Description |
| ---------- | ---------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `id` | string | No | ID is a unique identifier of this agent run. No other agent run with the same name must be managed by this agent manager |
| `metadata` | [Metadata](#type-gitpod-v1-agent-execution-metadata) | No | Metadata is data associated with this agent that's required for other parts of Gitpod to function |
| `spec` | [Spec](#type-gitpod-v1-agent-execution-spec) | No | Spec is the configuration of the agent that's required for the runner to start the agent |
| `status` | [Status](#type-gitpod-v1-agent-execution-status) | No | Status is the current status of the agent |
`gitpod.v1.AgentExecution.Metadata`
| Field | Type | Required | Description |
| ------------------ | ---------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | No | |
| `description` | string | No | |
| `creator` | Subject | No | |
| `createdAt` | RFC 3339 timestamp | No | |
| `updatedAt` | RFC 3339 timestamp | No | |
| `role` | [AgentExecutionRole](#enum-gitpod-v1-agent-execution-role) | No | role is the role of the agent execution |
| `workflowActionId` | string | No | workflow\_action\_id is set when this agent execution was created as part of a workflow. Used to correlate agent executions with their parent workflow execution action. Constraints: `ignore=1, string.uuid=true`. |
| `annotations` | map of string to string | No | annotations are key-value pairs for tracking external context. |
| `sessionId` | string | No | session\_id is the ID of the session this agent execution belongs to. |
`gitpod.v1.AgentExecution.Spec`
| Field | Type | Required | Description |
| --------------- | ---------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `specVersion` | 64-bit integer string | No | version of the spec. The value of this field has no semantic meaning (e.g. don't interpret it as as a timestamp), but it can be used to impose a partial order. If a.spec\_version \< b.spec\_version then a was the spec before b. |
| `session` | string | No | |
| `desiredPhase` | [Phase](#enum-gitpod-v1-agent-execution-phase) | No | desired\_phase is the desired phase of the agent run |
| `agentId` | string | No | Constraints: `string.uuid=true`. |
| `codeContext` | AgentCodeContext | No | |
| `limits` | Limits | No | |
| `codexSettings` | CodexSettings | No | codex\_settings contains persisted desired/manual settings for the Codex app agent. |
`gitpod.v1.AgentExecution.Status`
| Field | Type | Required | Description |
| -------------------------- | ----------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `statusVersion` | 64-bit integer string | No | version of the status. The value of this field has no semantic meaning (e.g. don't interpret it as as a timestamp), but it can be used to impose a partial order. If a.status\_version \< b.status\_version then a was the status before b. |
| `session` | string | No | |
| `phase` | [Phase](#enum-gitpod-v1-agent-execution-phase) | No | |
| `failureMessage` | string | No | failure\_message contains the reason the agent run failed to operate. |
| `warningMessage` | string | No | warning\_message contains warnings, e.g. when the LLM is overloaded. |
| `failureReason` | [AgentExecutionFailureReason](#enum-gitpod-v1-agent-execution-failure-reason) | No | failure\_reason contains a structured reason code for the failure. |
| `conversationUrl` | string | No | conversation\_url is the URL to the conversation (all messages exchanged between the agent and the user) of the agent run. |
| `transcriptUrl` | string | No | transcript\_url is the URL to the LLM transcript (all messages exchanged between the agent and the LLM) of the agent run. |
| `supportBundleUrl` | string | No | support\_bundle\_url is the URL to download a diagnostic bundle for this agent execution. |
| `conversationUrls` | ConversationURLs | No | conversation\_urls contains the v2 conversation streaming endpoints. When present, clients should use these URLs instead of conversation\_url. |
| `iterations` | 64-bit integer string | No | |
| `inputTokensUsed` | 64-bit integer string | No | |
| `outputTokensUsed` | 64-bit integer string | No | |
| `contextWindowLength` | 64-bit integer string | No | |
| `cachedCreationTokensUsed` | 64-bit integer string | No | |
| `cachedInputTokensUsed` | 64-bit integer string | No | |
| `contextWindowLimit` | 64-bit integer string | No | context\_window\_limit is the selected model's maximum context window size in tokens. |
| `judgement` | string | No | judgement is the judgement of the agent run produced by the judgement prompt. |
| `currentOperation` | CurrentOperation | No | current\_operation is the current operation of the agent execution. |
| `usedEnvironments` | array of EnvironmentUsage | No | used\_environments is the list of environments that were used by the agent execution. |
| `currentActivity` | string | No | current\_activity is the current activity description of the agent execution. |
| `outputs` | map of string to OutputValue | No | outputs is a map of key-value pairs that can be set by the agent during execution. Similar to task execution outputs, but with typed values for structured data. Constraints: `map.keys.string.max_len=128, map.keys.string.min_len=1`. |
| `supportedModel` | [SupportedModel](#enum-gitpod-v1-supported-model) | No | supported\_model is the LLM model being used by the agent execution. |
| `llmCapabilities` | LLMCapabilities | No | llm\_capabilities describes provider capabilities for the selected LLM integration. |
| `mode` | [AgentMode](#enum-gitpod-v1-agent-mode) | No | mode is the current operational mode of the agent execution. This is set by the agent when entering different modes (e.g., Ralph mode via /ona:ralph command). |
| `mcpIntegrationStatuses` | array of MCPIntegrationStatus | No | mcp\_integration\_statuses contains the status of all MCP integrations used by this agent execution |
| `waitingInfo` | WaitingInfo | No | waiting\_info is set when phase is PHASE\_WAITING\_FOR\_INPUT and the agent has registered interests (timers, sub-agent completions, user messages). |
| `terminalId` | string | No | terminal\_id is the ID of the terminal running the agent, if the agent runs as a terminal service (runsOn: terminal). |
| `goal` | Goal | No | goal projects the current agent goal, if any. |
| `codexSettings` | CodexSettings | No | codex\_settings contains runtime effective settings reported by the Codex app agent. |
| `subagents` | array of Subagent | No | |
| Value | Number | Description |
| ------------------------- | -----: | ----------------------------------- |
| `PHASE_UNSPECIFIED` | 0 | The phase is not set. |
| `PHASE_PENDING` | 10 | The agent run is pending. |
| `PHASE_RUNNING` | 20 | The agent run is active. |
| `PHASE_WAITING_FOR_INPUT` | 30 | The agent run is waiting for input. |
| `PHASE_STOPPED` | 40 | The agent run is inactive. |
AgentExecutionFailureReason represents the reason why an agent execution failed
| Value | Number | Description |
| ------------------------------------------------ | -----: | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `AGENT_EXECUTION_FAILURE_REASON_UNSPECIFIED` | 0 | |
| `AGENT_EXECUTION_FAILURE_REASON_ENVIRONMENT` | 1 | The agent execution failed due to environment issues |
| `AGENT_EXECUTION_FAILURE_REASON_SERVICE` | 2 | The agent execution failed due to service issues |
| `AGENT_EXECUTION_FAILURE_REASON_LLM_INTEGRATION` | 3 | The agent execution failed due to LLM integration issues |
| `AGENT_EXECUTION_FAILURE_REASON_INTERNAL` | 4 | **Deprecated.** Deprecated: The agent execution failed due to internal errors Use AGENT\_EXECUTION\_FAILURE\_REASON\_AGENT\_EXECUTION instead |
| `AGENT_EXECUTION_FAILURE_REASON_AGENT_EXECUTION` | 5 | The agent execution failed due to agent execution errors |
AgentExecutionRole represents the role of an agent execution
| Value | Number | Description |
| ---------------------------------- | -----: | -------------------------------------------------------------- |
| `AGENT_EXECUTION_ROLE_UNSPECIFIED` | 0 | |
| `AGENT_EXECUTION_ROLE_DEFAULT` | 1 | Default role for agent executions |
| `AGENT_EXECUTION_ROLE_WORKFLOW` | 2 | Workflow role for agent executions that are part of a workflow |
AgentMode defines the operational mode of an agent
| Value | Number | Description |
| ------------------------ | -----: | ----------------------------------------------------------------- |
| `AGENT_MODE_UNSPECIFIED` | 0 | Default execution mode - standard agent behavior |
| `AGENT_MODE_EXECUTION` | 1 | Execution mode - agent performs tasks and makes changes |
| `AGENT_MODE_PLANNING` | 2 | Planning mode - agent focuses on analysis and planning |
| `AGENT_MODE_RALPH` | 3 | Ralph mode - autonomous planning and implementation mode |
| `AGENT_MODE_SPEC` | 4 | Spec mode - planning phase followed by interactive implementation |
| `AGENT_MODE_GOAL` | 5 | Goal mode - agent treats the user input as a goal objective |
SupportedModel enumerates the LLM models available for agent executions
| Value | Number | Description |
| ------------------------------------- | -----: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SUPPORTED_MODEL_UNSPECIFIED` | 0 | |
| `SUPPORTED_MODEL_SONNET_3_5` | 1 | |
| `SUPPORTED_MODEL_SONNET_3_7` | 2 | |
| `SUPPORTED_MODEL_SONNET_3_7_EXTENDED` | 3 | |
| `SUPPORTED_MODEL_SONNET_4` | 4 | |
| `SUPPORTED_MODEL_SONNET_4_EXTENDED` | 5 | |
| `SUPPORTED_MODEL_SONNET_4_5` | 8 | |
| `SUPPORTED_MODEL_SONNET_4_5_EXTENDED` | 9 | |
| `SUPPORTED_MODEL_SONNET_4_6` | 18 | |
| `SUPPORTED_MODEL_SONNET_4_6_EXTENDED` | 19 | |
| `SUPPORTED_MODEL_SONNET_5` | 32 | |
| `SUPPORTED_MODEL_OPUS_4` | 6 | |
| `SUPPORTED_MODEL_OPUS_4_EXTENDED` | 7 | |
| `SUPPORTED_MODEL_OPUS_4_5` | 14 | |
| `SUPPORTED_MODEL_OPUS_4_5_EXTENDED` | 15 | |
| `SUPPORTED_MODEL_OPUS_4_6` | 16 | |
| `SUPPORTED_MODEL_OPUS_4_6_EXTENDED` | 17 | |
| `SUPPORTED_MODEL_OPUS_4_7` | 22 | |
| `SUPPORTED_MODEL_OPUS_4_8` | 31 | |
| `SUPPORTED_MODEL_HAIKU_4_5` | 21 | |
| `SUPPORTED_MODEL_OPENAI_4O` | 10 | |
| `SUPPORTED_MODEL_OPENAI_4O_MINI` | 11 | |
| `SUPPORTED_MODEL_OPENAI_O1` | 12 | |
| `SUPPORTED_MODEL_OPENAI_O1_MINI` | 13 | |
| `SUPPORTED_MODEL_OPENAI_AUTO` | 23 | SUPPORTED\_MODEL\_OPENAI\_AUTO flags a request as OpenAI-bound without encoding a specific model slug. The actual model is chosen by the client (today: native Codex via \~/.codex/config.toml) and captured from the upstream Responses-API response.model field for metering and rate-card lookup. This keeps the proto stable across OpenAI model-catalog churn. Reserved numbers 24-30 are intentionally left free for future OpenAI routing sentinels if we ever need to distinguish sub-families. |
# Get Prompt
Source: https://ona.com/docs/api-reference/generated/agent/get-prompt
Gets details about a specific prompt including name, description,
`Unary` · [`Agents`](/docs/api-reference/generated/agent/overview)
Gets details about a specific prompt including name, description,
and prompt content.
Use this method to:
* Retrieve prompt details for editing
* Get prompt content for execution
### Examples
* Get prompt details:
```yaml theme={null}
promptId: "07e03a28-65a5-4d98-b532-8ea67b188048"
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AgentService/GetPrompt
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AgentService/GetPrompt" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"promptId": ""
}'
```
```python Python theme={null}
import gitpod.v1.agent_pb2 as agent_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = agent_pb2.GetPromptRequest(
prompt_id="",
)
response = ona.services.agent.get_prompt(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { GetPromptRequestSchema } from "@gitpod/sdk/gitpod/v1/agent_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(GetPromptRequestSchema, {
promptId: "",
});
const response = await ona.services.agent.getPrompt(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.GetPromptRequest{
PromptId: "",
})
response, err := ona.Services.Agent.GetPrompt(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"promptId": ""
}
```
## Request
`gitpod.v1.GetPromptRequest`
| Field | Type | Required | Description |
| ---------- | ------ | -------- | -------------------------------- |
| `promptId` | string | No | Constraints: `string.uuid=true`. |
## Response
`gitpod.v1.GetPromptResponse`
| Field | Type | Required | Description |
| -------- | -------------------------------- | -------- | ----------- |
| `prompt` | [Prompt](#type-gitpod-v1-prompt) | No | |
## Related types
`gitpod.v1.Prompt`
| Field | Type | Required | Description |
| ---------- | ------------------------------------------------- | -------- | ----------- |
| `id` | string | No | |
| `metadata` | [PromptMetadata](#type-gitpod-v1-prompt-metadata) | No | |
| `spec` | [PromptSpec](#type-gitpod-v1-prompt-spec) | No | |
`gitpod.v1.PromptMetadata`
| Field | Type | Required | Description |
| ---------------- | ------------------ | -------- | -------------------------------------------------------------------------------------------------------- |
| `organizationId` | string | No | organization\_id is the ID of the organization that contains the prompt Constraints: `string.uuid=true`. |
| `name` | string | No | name is the human readable name of the prompt |
| `description` | string | No | description is a description of what the prompt does |
| `creator` | Subject | No | creator is the identity of the prompt creator |
| `createdAt` | RFC 3339 timestamp | No | |
| `updatedAt` | RFC 3339 timestamp | No | |
`gitpod.v1.PromptSpec`
| Field | Type | Required | Description |
| ------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `prompt` | string | No | prompt is the content of the prompt Constraints: `string.max_len=20000`. |
| `isTemplate` | boolean | No | is\_template indicates if this prompt is a template |
| `isCommand` | boolean | No | is\_command indicates if this prompt is a command |
| `command` | string | No | command is the unique command string within the organization Constraints: `string.max_len=50, string.pattern=^[a-zA-Z0-9_-]*$`. |
| `isSkill` | boolean | No | is\_skill indicates if this prompt is a skill (workflow instructions for agents) |
# List Agent Executions
Source: https://ona.com/docs/api-reference/generated/agent/list-agent-executions
Lists all agent runs matching the specified filter.
`Unary` · [`Agents`](/docs/api-reference/generated/agent/overview)
Lists all agent runs matching the specified filter.
Use this method to track multiple agent runs and their associated resources. Results are ordered by their creation time with the newest first.
### Examples
* List agent runs by agent ID:
```yaml theme={null}
filter:
agentIds: ["b8a64cfa-43e2-4b9d-9fb3-07edc63f5971"]
pagination:
pageSize: 10
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AgentService/ListAgentExecutions
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AgentService/ListAgentExecutions" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"pagination": {
"pageSize": 1
}
}'
```
```python Python theme={null}
import gitpod.v1.agent_pb2 as agent_pb2
import gitpod.v1.pagination_pb2 as pagination_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = agent_pb2.ListAgentExecutionsRequest(
pagination=pagination_pb2.PaginationRequest(
page_size=1,
),
)
response = ona.services.agent.list_agent_executions(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { ListAgentExecutionsRequestSchema } from "@gitpod/sdk/gitpod/v1/agent_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(ListAgentExecutionsRequestSchema, {
pagination: {
pageSize: 1,
},
});
const response = await ona.services.agent.listAgentExecutions(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.ListAgentExecutionsRequest{
Pagination: &gitpodpb.PaginationRequest{
PageSize: 1,
},
})
response, err := ona.Services.Agent.ListAgentExecutions(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"pagination": {
"pageSize": 1
}
}
```
## Request
`gitpod.v1.ListAgentExecutionsRequest`
| Field | Type | Required | Description |
| ------------ | -------------------------------------------------------------- | -------- | ----------- |
| `pagination` | [PaginationRequest](#type-gitpod-v1-pagination-request) | No | |
| `filter` | [Filter](#type-gitpod-v1-list-agent-executions-request-filter) | No | |
## Response
`gitpod.v1.ListAgentExecutionsResponse`
| Field | Type | Required | Description |
| ----------------- | ---------------------------------------------------------- | -------- | ----------- |
| `pagination` | [PaginationResponse](#type-gitpod-v1-pagination-response) | No | |
| `agentExecutions` | array of [AgentExecution](#type-gitpod-v1-agent-execution) | No | |
## Related types
`gitpod.v1.AgentExecution`
| Field | Type | Required | Description |
| ---------- | ---------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `id` | string | No | ID is a unique identifier of this agent run. No other agent run with the same name must be managed by this agent manager |
| `metadata` | [Metadata](#type-gitpod-v1-agent-execution-metadata) | No | Metadata is data associated with this agent that's required for other parts of Gitpod to function |
| `spec` | [Spec](#type-gitpod-v1-agent-execution-spec) | No | Spec is the configuration of the agent that's required for the runner to start the agent |
| `status` | [Status](#type-gitpod-v1-agent-execution-status) | No | Status is the current status of the agent |
`gitpod.v1.AgentExecution.Metadata`
| Field | Type | Required | Description |
| ------------------ | ---------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | No | |
| `description` | string | No | |
| `creator` | Subject | No | |
| `createdAt` | RFC 3339 timestamp | No | |
| `updatedAt` | RFC 3339 timestamp | No | |
| `role` | [AgentExecutionRole](#enum-gitpod-v1-agent-execution-role) | No | role is the role of the agent execution |
| `workflowActionId` | string | No | workflow\_action\_id is set when this agent execution was created as part of a workflow. Used to correlate agent executions with their parent workflow execution action. Constraints: `ignore=1, string.uuid=true`. |
| `annotations` | map of string to string | No | annotations are key-value pairs for tracking external context. |
| `sessionId` | string | No | session\_id is the ID of the session this agent execution belongs to. |
`gitpod.v1.AgentExecution.Spec`
| Field | Type | Required | Description |
| --------------- | ---------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `specVersion` | 64-bit integer string | No | version of the spec. The value of this field has no semantic meaning (e.g. don't interpret it as as a timestamp), but it can be used to impose a partial order. If a.spec\_version \< b.spec\_version then a was the spec before b. |
| `session` | string | No | |
| `desiredPhase` | [Phase](#enum-gitpod-v1-agent-execution-phase) | No | desired\_phase is the desired phase of the agent run |
| `agentId` | string | No | Constraints: `string.uuid=true`. |
| `codeContext` | AgentCodeContext | No | |
| `limits` | Limits | No | |
| `codexSettings` | CodexSettings | No | codex\_settings contains persisted desired/manual settings for the Codex app agent. |
`gitpod.v1.AgentExecution.Status`
| Field | Type | Required | Description |
| -------------------------- | ----------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `statusVersion` | 64-bit integer string | No | version of the status. The value of this field has no semantic meaning (e.g. don't interpret it as as a timestamp), but it can be used to impose a partial order. If a.status\_version \< b.status\_version then a was the status before b. |
| `session` | string | No | |
| `phase` | [Phase](#enum-gitpod-v1-agent-execution-phase) | No | |
| `failureMessage` | string | No | failure\_message contains the reason the agent run failed to operate. |
| `warningMessage` | string | No | warning\_message contains warnings, e.g. when the LLM is overloaded. |
| `failureReason` | [AgentExecutionFailureReason](#enum-gitpod-v1-agent-execution-failure-reason) | No | failure\_reason contains a structured reason code for the failure. |
| `conversationUrl` | string | No | conversation\_url is the URL to the conversation (all messages exchanged between the agent and the user) of the agent run. |
| `transcriptUrl` | string | No | transcript\_url is the URL to the LLM transcript (all messages exchanged between the agent and the LLM) of the agent run. |
| `supportBundleUrl` | string | No | support\_bundle\_url is the URL to download a diagnostic bundle for this agent execution. |
| `conversationUrls` | ConversationURLs | No | conversation\_urls contains the v2 conversation streaming endpoints. When present, clients should use these URLs instead of conversation\_url. |
| `iterations` | 64-bit integer string | No | |
| `inputTokensUsed` | 64-bit integer string | No | |
| `outputTokensUsed` | 64-bit integer string | No | |
| `contextWindowLength` | 64-bit integer string | No | |
| `cachedCreationTokensUsed` | 64-bit integer string | No | |
| `cachedInputTokensUsed` | 64-bit integer string | No | |
| `contextWindowLimit` | 64-bit integer string | No | context\_window\_limit is the selected model's maximum context window size in tokens. |
| `judgement` | string | No | judgement is the judgement of the agent run produced by the judgement prompt. |
| `currentOperation` | CurrentOperation | No | current\_operation is the current operation of the agent execution. |
| `usedEnvironments` | array of EnvironmentUsage | No | used\_environments is the list of environments that were used by the agent execution. |
| `currentActivity` | string | No | current\_activity is the current activity description of the agent execution. |
| `outputs` | map of string to OutputValue | No | outputs is a map of key-value pairs that can be set by the agent during execution. Similar to task execution outputs, but with typed values for structured data. Constraints: `map.keys.string.max_len=128, map.keys.string.min_len=1`. |
| `supportedModel` | [SupportedModel](#enum-gitpod-v1-supported-model) | No | supported\_model is the LLM model being used by the agent execution. |
| `llmCapabilities` | LLMCapabilities | No | llm\_capabilities describes provider capabilities for the selected LLM integration. |
| `mode` | [AgentMode](#enum-gitpod-v1-agent-mode) | No | mode is the current operational mode of the agent execution. This is set by the agent when entering different modes (e.g., Ralph mode via /ona:ralph command). |
| `mcpIntegrationStatuses` | array of MCPIntegrationStatus | No | mcp\_integration\_statuses contains the status of all MCP integrations used by this agent execution |
| `waitingInfo` | WaitingInfo | No | waiting\_info is set when phase is PHASE\_WAITING\_FOR\_INPUT and the agent has registered interests (timers, sub-agent completions, user messages). |
| `terminalId` | string | No | terminal\_id is the ID of the terminal running the agent, if the agent runs as a terminal service (runsOn: terminal). |
| `goal` | Goal | No | goal projects the current agent goal, if any. |
| `codexSettings` | CodexSettings | No | codex\_settings contains runtime effective settings reported by the Codex app agent. |
| `subagents` | array of Subagent | No | |
`gitpod.v1.ListAgentExecutionsRequest.Filter`
| Field | Type | Required | Description |
| ------------------- | ------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agentIds` | array of string | No | Constraints: `repeated.max_items=25, repeated.min_items=0`. |
| `projectIds` | array of string | No | Constraints: `repeated.items.string.uuid=true, repeated.max_items=25, repeated.min_items=0`. |
| `environmentIds` | array of string | No | Constraints: `repeated.max_items=25, repeated.min_items=0`. |
| `creatorIds` | array of string | No | Constraints: `repeated.max_items=25, repeated.min_items=0`. |
| `statusPhases` | array of [Phase](#enum-gitpod-v1-agent-execution-phase) | No | Constraints: `repeated.max_items=25, repeated.min_items=0`. |
| `roles` | array of [AgentExecutionRole](#enum-gitpod-v1-agent-execution-role) | No | Constraints: `repeated.items.enum.defined_only=true, repeated.max_items=25, repeated.min_items=0`. |
| `annotations` | map of string to string | No | annotations filters by key-value pairs. Only executions containing all specified annotations (with matching values) are returned. |
| `sessionIds` | array of string | No | session\_ids filters the response to only executions belonging to the specified sessions Constraints: `repeated.items.string.uuid=true, repeated.max_items=25, repeated.min_items=0`. |
| `agentExecutionIds` | array of string | No | agent\_execution\_ids filters the response to only the specified executions. Useful for checking existence of a known set of execution IDs. Constraints: `repeated.items.string.uuid=true, repeated.max_items=100, repeated.min_items=0`. |
`gitpod.v1.PaginationRequest`
| Field | Type | Required | Description |
| ---------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `pageSize` | integer | No | Page size is the maximum number of results to retrieve per page. Defaults to 25. Maximum 100. Constraints: `int32.gte=0, int32.lte=100`. |
| `token` | string | No | Token for the next set of results that was returned as next\_token of a PaginationResponse |
`gitpod.v1.PaginationResponse`
| Field | Type | Required | Description |
| ----------- | ------ | -------- | --------------------------------------------------------------------------------------- |
| `nextToken` | string | No | Token passed for retrieving the next set of results. Empty if there are no more results |
| Value | Number | Description |
| ------------------------- | -----: | ----------------------------------- |
| `PHASE_UNSPECIFIED` | 0 | The phase is not set. |
| `PHASE_PENDING` | 10 | The agent run is pending. |
| `PHASE_RUNNING` | 20 | The agent run is active. |
| `PHASE_WAITING_FOR_INPUT` | 30 | The agent run is waiting for input. |
| `PHASE_STOPPED` | 40 | The agent run is inactive. |
AgentExecutionFailureReason represents the reason why an agent execution failed
| Value | Number | Description |
| ------------------------------------------------ | -----: | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `AGENT_EXECUTION_FAILURE_REASON_UNSPECIFIED` | 0 | |
| `AGENT_EXECUTION_FAILURE_REASON_ENVIRONMENT` | 1 | The agent execution failed due to environment issues |
| `AGENT_EXECUTION_FAILURE_REASON_SERVICE` | 2 | The agent execution failed due to service issues |
| `AGENT_EXECUTION_FAILURE_REASON_LLM_INTEGRATION` | 3 | The agent execution failed due to LLM integration issues |
| `AGENT_EXECUTION_FAILURE_REASON_INTERNAL` | 4 | **Deprecated.** Deprecated: The agent execution failed due to internal errors Use AGENT\_EXECUTION\_FAILURE\_REASON\_AGENT\_EXECUTION instead |
| `AGENT_EXECUTION_FAILURE_REASON_AGENT_EXECUTION` | 5 | The agent execution failed due to agent execution errors |
AgentExecutionRole represents the role of an agent execution
| Value | Number | Description |
| ---------------------------------- | -----: | -------------------------------------------------------------- |
| `AGENT_EXECUTION_ROLE_UNSPECIFIED` | 0 | |
| `AGENT_EXECUTION_ROLE_DEFAULT` | 1 | Default role for agent executions |
| `AGENT_EXECUTION_ROLE_WORKFLOW` | 2 | Workflow role for agent executions that are part of a workflow |
AgentMode defines the operational mode of an agent
| Value | Number | Description |
| ------------------------ | -----: | ----------------------------------------------------------------- |
| `AGENT_MODE_UNSPECIFIED` | 0 | Default execution mode - standard agent behavior |
| `AGENT_MODE_EXECUTION` | 1 | Execution mode - agent performs tasks and makes changes |
| `AGENT_MODE_PLANNING` | 2 | Planning mode - agent focuses on analysis and planning |
| `AGENT_MODE_RALPH` | 3 | Ralph mode - autonomous planning and implementation mode |
| `AGENT_MODE_SPEC` | 4 | Spec mode - planning phase followed by interactive implementation |
| `AGENT_MODE_GOAL` | 5 | Goal mode - agent treats the user input as a goal objective |
SupportedModel enumerates the LLM models available for agent executions
| Value | Number | Description |
| ------------------------------------- | -----: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SUPPORTED_MODEL_UNSPECIFIED` | 0 | |
| `SUPPORTED_MODEL_SONNET_3_5` | 1 | |
| `SUPPORTED_MODEL_SONNET_3_7` | 2 | |
| `SUPPORTED_MODEL_SONNET_3_7_EXTENDED` | 3 | |
| `SUPPORTED_MODEL_SONNET_4` | 4 | |
| `SUPPORTED_MODEL_SONNET_4_EXTENDED` | 5 | |
| `SUPPORTED_MODEL_SONNET_4_5` | 8 | |
| `SUPPORTED_MODEL_SONNET_4_5_EXTENDED` | 9 | |
| `SUPPORTED_MODEL_SONNET_4_6` | 18 | |
| `SUPPORTED_MODEL_SONNET_4_6_EXTENDED` | 19 | |
| `SUPPORTED_MODEL_SONNET_5` | 32 | |
| `SUPPORTED_MODEL_OPUS_4` | 6 | |
| `SUPPORTED_MODEL_OPUS_4_EXTENDED` | 7 | |
| `SUPPORTED_MODEL_OPUS_4_5` | 14 | |
| `SUPPORTED_MODEL_OPUS_4_5_EXTENDED` | 15 | |
| `SUPPORTED_MODEL_OPUS_4_6` | 16 | |
| `SUPPORTED_MODEL_OPUS_4_6_EXTENDED` | 17 | |
| `SUPPORTED_MODEL_OPUS_4_7` | 22 | |
| `SUPPORTED_MODEL_OPUS_4_8` | 31 | |
| `SUPPORTED_MODEL_HAIKU_4_5` | 21 | |
| `SUPPORTED_MODEL_OPENAI_4O` | 10 | |
| `SUPPORTED_MODEL_OPENAI_4O_MINI` | 11 | |
| `SUPPORTED_MODEL_OPENAI_O1` | 12 | |
| `SUPPORTED_MODEL_OPENAI_O1_MINI` | 13 | |
| `SUPPORTED_MODEL_OPENAI_AUTO` | 23 | SUPPORTED\_MODEL\_OPENAI\_AUTO flags a request as OpenAI-bound without encoding a specific model slug. The actual model is chosen by the client (today: native Codex via \~/.codex/config.toml) and captured from the upstream Responses-API response.model field for metering and rate-card lookup. This keeps the proto stable across OpenAI model-catalog churn. Reserved numbers 24-30 are intentionally left free for future OpenAI routing sentinels if we ever need to distinguish sub-families. |
# List Prompts
Source: https://ona.com/docs/api-reference/generated/agent/list-prompts
Lists all prompts matching the specified criteria.
`Unary` · [`Agents`](/docs/api-reference/generated/agent/overview)
Lists all prompts matching the specified criteria.
Use this method to find and browse prompts across your organization.
Results are ordered by their creation time with the newest first.
### Examples
* List all prompts:
Retrieves all prompts with pagination.
```yaml theme={null}
pagination:
pageSize: 10
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AgentService/ListPrompts
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AgentService/ListPrompts" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"pagination": {
"pageSize": 1
}
}'
```
```python Python theme={null}
import gitpod.v1.agent_pb2 as agent_pb2
import gitpod.v1.pagination_pb2 as pagination_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = agent_pb2.ListPromptsRequest(
pagination=pagination_pb2.PaginationRequest(
page_size=1,
),
)
response = ona.services.agent.list_prompts(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { ListPromptsRequestSchema } from "@gitpod/sdk/gitpod/v1/agent_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(ListPromptsRequestSchema, {
pagination: {
pageSize: 1,
},
});
const response = await ona.services.agent.listPrompts(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.ListPromptsRequest{
Pagination: &gitpodpb.PaginationRequest{
PageSize: 1,
},
})
response, err := ona.Services.Agent.ListPrompts(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"pagination": {
"pageSize": 1
}
}
```
## Request
`gitpod.v1.ListPromptsRequest`
| Field | Type | Required | Description |
| ------------ | ------------------------------------------------------- | -------- | ----------- |
| `pagination` | [PaginationRequest](#type-gitpod-v1-pagination-request) | No | |
| `filter` | [Filter](#type-gitpod-v1-list-prompts-request-filter) | No | |
## Response
`gitpod.v1.ListPromptsResponse`
| Field | Type | Required | Description |
| ------------ | --------------------------------------------------------- | -------- | ----------- |
| `pagination` | [PaginationResponse](#type-gitpod-v1-pagination-response) | No | |
| `prompts` | array of [Prompt](#type-gitpod-v1-prompt) | No | |
## Related types
`gitpod.v1.ListPromptsRequest.Filter`
| Field | Type | Required | Description |
| ---------------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `isTemplate` | boolean | No | |
| `isCommand` | boolean | No | |
| `command` | string | No | |
| `commandPrefix` | string | No | Constraints: `string.max_len=50`. |
| `isSkill` | boolean | No | |
| `excludePromptContent` | boolean | No | exclude\_prompt\_content omits the large spec.prompt text from the response. Other spec fields (is\_template, is\_command, command, is\_skill) are still returned. Use GetPrompt to retrieve the full prompt content when needed. |
| `search` | string | No | search performs case-insensitive search across prompt name, description, and command. Constraints: `string.max_len=256`. |
`gitpod.v1.PaginationRequest`
| Field | Type | Required | Description |
| ---------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `pageSize` | integer | No | Page size is the maximum number of results to retrieve per page. Defaults to 25. Maximum 100. Constraints: `int32.gte=0, int32.lte=100`. |
| `token` | string | No | Token for the next set of results that was returned as next\_token of a PaginationResponse |
`gitpod.v1.PaginationResponse`
| Field | Type | Required | Description |
| ----------- | ------ | -------- | --------------------------------------------------------------------------------------- |
| `nextToken` | string | No | Token passed for retrieving the next set of results. Empty if there are no more results |
`gitpod.v1.Prompt`
| Field | Type | Required | Description |
| ---------- | ------------------------------------------------- | -------- | ----------- |
| `id` | string | No | |
| `metadata` | [PromptMetadata](#type-gitpod-v1-prompt-metadata) | No | |
| `spec` | [PromptSpec](#type-gitpod-v1-prompt-spec) | No | |
`gitpod.v1.PromptMetadata`
| Field | Type | Required | Description |
| ---------------- | ------------------ | -------- | -------------------------------------------------------------------------------------------------------- |
| `organizationId` | string | No | organization\_id is the ID of the organization that contains the prompt Constraints: `string.uuid=true`. |
| `name` | string | No | name is the human readable name of the prompt |
| `description` | string | No | description is a description of what the prompt does |
| `creator` | Subject | No | creator is the identity of the prompt creator |
| `createdAt` | RFC 3339 timestamp | No | |
| `updatedAt` | RFC 3339 timestamp | No | |
`gitpod.v1.PromptSpec`
| Field | Type | Required | Description |
| ------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `prompt` | string | No | prompt is the content of the prompt Constraints: `string.max_len=20000`. |
| `isTemplate` | boolean | No | is\_template indicates if this prompt is a template |
| `isCommand` | boolean | No | is\_command indicates if this prompt is a command |
| `command` | string | No | command is the unique command string within the organization Constraints: `string.max_len=50, string.pattern=^[a-zA-Z0-9_-]*$`. |
| `isSkill` | boolean | No | is\_skill indicates if this prompt is a skill (workflow instructions for agents) |
# Agents
Source: https://ona.com/docs/api-reference/generated/agent/overview
Reference for the Agents API methods.
## Methods
Creates a token for conversation access with a specific agent run.
Creates a new prompt.
Deletes an agent run.
Deletes a prompt.
Gets details about a specific agent run, including its metadata, specification,
Gets details about a specific prompt including name, description,
Lists all agent runs matching the specified filter.
Lists all prompts matching the specified criteria.
Sends user input to an active agent run.
Starts (or triggers) an agent run using a provided agent.
Stops an active agent execution.
Updates an existing prompt.
# Send To Agent Execution
Source: https://ona.com/docs/api-reference/generated/agent/send-to-agent-execution
Sends user input to an active agent run.
`Unary` · [`Agents`](/docs/api-reference/generated/agent/overview)
Sends user input to an active agent run.
This method is used to provide interactive or conversation-based input
to an agent. The agent can respond with output blocks containing
text, file changes, or tool usage requests.
### Examples
* Send a text message to an agent:
```yaml theme={null}
agentExecutionId: "6fa1a3c7-fbb7-49d1-ba56-1890dc7c4c35"
userInput:
text:
content: "Generate a report based on the latest logs."
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AgentService/SendToAgentExecution
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AgentService/SendToAgentExecution" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"agentExecutionId": ""
}'
```
```python Python theme={null}
import gitpod.v1.agent_pb2 as agent_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = agent_pb2.SendToAgentExecutionRequest(
agent_execution_id="",
)
response = ona.services.agent.send_to_agent_execution(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { SendToAgentExecutionRequestSchema } from "@gitpod/sdk/gitpod/v1/agent_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(SendToAgentExecutionRequestSchema, {
agentExecutionId: "",
});
const response = await ona.services.agent.sendToAgentExecution(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.SendToAgentExecutionRequest{
AgentExecutionId: "",
})
response, err := ona.Services.Agent.SendToAgentExecution(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"agentExecutionId": ""
}
```
## Request
`gitpod.v1.SendToAgentExecutionRequest`
| Field | Type | Required | Description |
| ------------------ | -------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------- |
| `agentExecutionId` | string | No | Constraints: `string.uuid=true`. |
| `userInput` | [UserInputBlock](#type-gitpod-v1-user-input-block) | No | |
| `agentMessage` | [AgentMessage](#type-gitpod-v1-agent-message) | No | |
| `wakeEvent` | [WakeEvent](#type-gitpod-v1-wake-event) | No | |
| `controlInput` | [AgentControlInput](#type-gitpod-v1-agent-control-input) | No | |
| `codexSettings` | [CodexSettings](#type-gitpod-v1-codex-settings) | No | codex\_settings contains per-turn desired settings for Codex app user\_input sends. |
| `turnOptions` | [TurnOptions](#type-gitpod-v1-turn-options) | No | turn\_options contains options that apply to this submitted turn. |
## Response
`gitpod.v1.SendToAgentExecutionResponse`
This message has no fields.
## Related types
`gitpod.v1.AgentControlInput`
| Field | Type | Required | Description |
| --------------------- | -------------------------------------------------------------------------------- | -------- | ----------- |
| `compact` | [Compact](#type-gitpod-v1-agent-control-input-compact) | No | |
| `goal` | [Goal](#type-gitpod-v1-agent-control-input-goal) | No | |
| `deleteQueuedMessage` | [DeleteQueuedMessage](#type-gitpod-v1-agent-control-input-delete-queued-message) | No | |
| `steerQueuedMessage` | [SteerQueuedMessage](#type-gitpod-v1-agent-control-input-steer-queued-message) | No | |
| `moveQueuedMessage` | [MoveQueuedMessage](#type-gitpod-v1-agent-control-input-move-queued-message) | No | |
`gitpod.v1.AgentControlInput.Compact`
This message has no fields.
`gitpod.v1.AgentControlInput.DeleteQueuedMessage`
| Field | Type | Required | Description |
| ------------- | ------ | -------- | -------------------------------- |
| `userInputId` | string | No | Constraints: `string.min_len=1`. |
`gitpod.v1.AgentControlInput.Goal`
| Field | Type | Required | Description |
| ---------- | -------- | -------- | ----------- |
| `pause` | Pause | No | |
| `resume` | Resume | No | |
| `complete` | Complete | No | |
| `clear` | Clear | No | |
| `set` | Set | No | |
`gitpod.v1.AgentControlInput.MoveQueuedMessage`
| Field | Type | Required | Description |
| ------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------- |
| `userInputId` | string | No | Constraints: `string.min_len=1`. |
| `beforeUserInputId` | string | No | before\_user\_input\_id is the queued user input to insert before. Empty means move to the end. |
`gitpod.v1.AgentControlInput.SteerQueuedMessage`
| Field | Type | Required | Description |
| ------------- | ------ | -------- | -------------------------------- |
| `userInputId` | string | No | Constraints: `string.min_len=1`. |
AgentMessage is a message sent between agents (e.g. from a parent agent to a
child agent execution, or vice versa).
`gitpod.v1.AgentMessage`
| Field | Type | Required | Description |
| ------------------- | ------------------------------------------ | -------- | ----------------------------------------------------- |
| `type` | [Type](#enum-gitpod-v1-agent-message-type) | No | |
| `payload` | string | No | Free-form payload of the message. |
| `role` | [Role](#enum-gitpod-v1-agent-message-role) | No | The role of the sender in the agent hierarchy. |
| `senderExecutionId` | string | No | The execution ID of the agent that sent this message. |
CodexSettings contains settings consumed only by the Codex app agent.
`gitpod.v1.CodexSettings`
| Field | Type | Required | Description |
| ----------------- | -------------------------------------------------------------- | -------- | -------------------------------------- |
| `model` | [CodexOpenAIModel](#enum-gitpod-v1-codex-open-ai-model) | No | Constraints: `enum.defined_only=true`. |
| `reasoningEffort` | [CodexReasoningEffort](#enum-gitpod-v1-codex-reasoning-effort) | No | Constraints: `enum.defined_only=true`. |
| `serviceTier` | [CodexServiceTier](#enum-gitpod-v1-codex-service-tier) | No | Constraints: `enum.defined_only=true`. |
`gitpod.v1.TurnOptions`
| Field | Type | Required | Description |
| ------- | ------------------------------------------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `modes` | array of [AgentMode](#enum-gitpod-v1-agent-mode) | No | modes contains requested modes for this turn. Agents decide whether a mode remains active after the submitted turn and report durable state via AgentExecution.Status. Constraints: `repeated.max_items=4`. |
`gitpod.v1.UserInputBlock`
| Field | Type | Required | Description |
| ----------- | ---------------------------------------------------------- | -------- | ------------------------------------------------------------------------------ |
| `id` | string | No | |
| `text` | [TextInput](#type-gitpod-v1-user-input-block-text-input) | No | **Deprecated.** |
| `image` | [ImageInput](#type-gitpod-v1-user-input-block-image-input) | No | **Deprecated.** |
| `inputs` | array of [Input](#type-gitpod-v1-user-input-block-input) | No | Constraints: `repeated.max_items=10`. |
| `createdAt` | RFC 3339 timestamp | No | Timestamp when this block was created. Used for debugging and support bundles. |
| `metadata` | [UserInputMetadata](#type-gitpod-v1-user-input-metadata) | No | Integration-specific metadata for this input. |
ImageInput allows sending images to the agent.
Client must provide the MIME type; backend validates against magic bytes.
`gitpod.v1.UserInputBlock.ImageInput`
| Field | Type | Required | Description |
| ---------- | ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data` | base64 string | No | Raw image data (max 4MB). Supported formats: PNG, JPEG. Constraints: `bytes.max_len=4194304, bytes.min_len=1`. |
| `mimeType` | string | No | Constraints: `string.in=image/jpeg, string.in=image/png`. |
| `dataRef` | string | No | Content-addressed reference to offloaded image data. Set by the runner when storing in the conversation store; data is cleared. Clients never send this field. |
`gitpod.v1.UserInputBlock.Input`
| Field | Type | Required | Description |
| ------- | ---------- | -------------- | ----------- |
| `text` | TextInput | One of `input` | |
| `image` | ImageInput | One of `input` | |
`gitpod.v1.UserInputBlock.TextInput`
| Field | Type | Required | Description |
| --------- | ------ | -------- | -------------------------------- |
| `content` | string | No | Constraints: `string.min_len=1`. |
UserInputMetadata carries integration-specific context for a user input.
Internal only - not exposed in public SDKs. External API consumers should
not set these fields; they are populated by integration handlers.
`gitpod.v1.UserInputMetadata`
| Field | Type | Required | Description |
| -------- | ------------------------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `source` | string | No | Origin of this input - set by integration handlers to their host (e.g. "github.com", "slack.com"). Empty for non-integration callers. This field drives emission gating: when set, agent responses are only emitted to the matching integration. Treated as trusted input from integration handlers; not validated against registered hosts. |
| `modes` | array of [AgentMode](#enum-gitpod-v1-agent-mode) | No | modes records the structured modes requested for this user input. When present, clients should prefer these modes over legacy prompt prefixes for rendering user-message labels. Constraints: `repeated.max_items=4`. |
WakeEvent is sent by the backend to wake an agent when a registered interest fires.
Delivered via SendToAgentExecution as a new oneof variant.
`gitpod.v1.WakeEvent`
| Field | Type | Required | Description |
| --------------------- | --------------------------------------------------------------------------------- | -------- | ---------------------------------------------------------- |
| `interestId` | string | No | The interest ID that fired (from WaitingInfo.Interest.id). |
| `timer` | [TimerFired](#type-gitpod-v1-wake-event-timer-fired) | No | |
| `loopRetrigger` | [LoopRetrigger](#type-gitpod-v1-wake-event-loop-retrigger) | No | |
| `environment` | [EnvironmentPhaseReached](#type-gitpod-v1-wake-event-environment-phase-reached) | No | |
| `devcontainerRebuild` | [DevcontainerPhaseReached](#type-gitpod-v1-wake-event-devcontainer-phase-reached) | No | |
`gitpod.v1.WakeEvent.DevcontainerPhaseReached`
| Field | Type | Required | Description |
| ---------------- | --------------- | -------- | ----------------------------------------------------- |
| `environmentId` | string | No | |
| `phase` | string | No | The devcontainer phase reached by the target session. |
| `sessionId` | string | No | |
| `failureMessage` | array of string | No | |
`gitpod.v1.WakeEvent.EnvironmentPhaseReached`
| Field | Type | Required | Description |
| ---------------- | --------------- | -------- | ------------------------------------------------------------------------- |
| `environmentId` | string | No | |
| `phase` | string | No | The phase the environment reached (e.g. "running", "stopped", "deleted"). |
| `failureMessage` | array of string | No | |
`gitpod.v1.WakeEvent.LoopRetrigger`
| Field | Type | Required | Description |
| ----------------- | ----------------------- | -------- | ----------- |
| `unmetConditions` | array of UnmetCondition | No | |
| `outputs` | map of string to string | No | |
`gitpod.v1.WakeEvent.TimerFired`
| Field | Type | Required | Description |
| --------- | ------------------ | -------- | --------------------------------------------------- |
| `firedAt` | RFC 3339 timestamp | No | The actual time the timer was evaluated as expired. |
Role identifies the sender's relationship in the parent/child hierarchy.
| Value | Number | Description |
| ------------------ | -----: | ---------------------------------- |
| `ROLE_UNSPECIFIED` | 0 | |
| `ROLE_PARENT` | 1 | The sender is the parent agent. |
| `ROLE_CHILD` | 2 | The sender is a child (sub-agent). |
| Value | Number | Description |
| ------------------ | -----: | ------------------------------------------------------ |
| `TYPE_UNSPECIFIED` | 0 | |
| `TYPE_UPDATE` | 1 | Regular inter-agent update message. |
| `TYPE_COMPLETE` | 2 | Signals that the sending agent has completed its task. |
AgentMode defines the operational mode of an agent
| Value | Number | Description |
| ------------------------ | -----: | ----------------------------------------------------------------- |
| `AGENT_MODE_UNSPECIFIED` | 0 | Default execution mode - standard agent behavior |
| `AGENT_MODE_EXECUTION` | 1 | Execution mode - agent performs tasks and makes changes |
| `AGENT_MODE_PLANNING` | 2 | Planning mode - agent focuses on analysis and planning |
| `AGENT_MODE_RALPH` | 3 | Ralph mode - autonomous planning and implementation mode |
| `AGENT_MODE_SPEC` | 4 | Spec mode - planning phase followed by interactive implementation |
| `AGENT_MODE_GOAL` | 5 | Goal mode - agent treats the user input as a goal objective |
CodexOpenAIModel is the static allowlist of concrete OpenAI models that the
Codex app runtime can select through Ona's Codex picker.
| Value | Number | Description |
| ----------------------------------------- | -----: | --------------- |
| `CODEX_OPEN_AI_MODEL_UNSPECIFIED` | 0 | |
| `CODEX_OPEN_AI_MODEL_GPT_5_5` | 1 | |
| `CODEX_OPEN_AI_MODEL_GPT_5_4` | 2 | |
| `CODEX_OPEN_AI_MODEL_GPT_5_4_MINI` | 3 | **Deprecated.** |
| `CODEX_OPEN_AI_MODEL_GPT_5_3_CODEX` | 4 | **Deprecated.** |
| `CODEX_OPEN_AI_MODEL_GPT_5_3_CODEX_SPARK` | 5 | **Deprecated.** |
| `CODEX_OPEN_AI_MODEL_GPT_5_2` | 6 | **Deprecated.** |
| `CODEX_OPEN_AI_MODEL_GPT_5_6_SOL` | 7 | |
| `CODEX_OPEN_AI_MODEL_GPT_5_6_TERRA` | 8 | |
| `CODEX_OPEN_AI_MODEL_GPT_5_6_LUNA` | 9 | |
CodexReasoningEffort is the static allowlist of reasoning efforts supported
by the Codex app runtime.
| Value | Number | Description |
| ------------------------------------ | -----: | ----------- |
| `CODEX_REASONING_EFFORT_UNSPECIFIED` | 0 | |
| `CODEX_REASONING_EFFORT_LOW` | 1 | |
| `CODEX_REASONING_EFFORT_MEDIUM` | 2 | |
| `CODEX_REASONING_EFFORT_HIGH` | 3 | |
| `CODEX_REASONING_EFFORT_EXTRA_HIGH` | 4 | |
| `CODEX_REASONING_EFFORT_MAX` | 5 | |
| `CODEX_REASONING_EFFORT_ULTRA` | 6 | |
CodexServiceTier is the static allowlist of service tiers supported by the
Codex app runtime.
| Value | Number | Description |
| -------------------------------- | -----: | ----------- |
| `CODEX_SERVICE_TIER_UNSPECIFIED` | 0 | |
| `CODEX_SERVICE_TIER_FAST` | 1 | |
# Start Agent
Source: https://ona.com/docs/api-reference/generated/agent/start-agent
Starts (or triggers) an agent run using a provided agent.
`Unary` · [`Agents`](/docs/api-reference/generated/agent/overview)
Starts (or triggers) an agent run using a provided agent.
Use this method to:
* Launch an agent based on a known agent
### Examples
* Start an agent with a project ID:
```yaml theme={null}
agentId: "b8a64cfa-43e2-4b9d-9fb3-07edc63f5971"
codeContext:
projectId: "2d22e4eb-31da-467f-882c-27e21550992f"
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AgentService/StartAgent
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AgentService/StartAgent" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"agentId": ""
}'
```
```python Python theme={null}
import gitpod.v1.agent_pb2 as agent_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = agent_pb2.StartAgentRequest(
agent_id="",
)
response = ona.services.agent.start_agent(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { StartAgentRequestSchema } from "@gitpod/sdk/gitpod/v1/agent_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(StartAgentRequestSchema, {
agentId: "",
});
const response = await ona.services.agent.startAgent(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.StartAgentRequest{
AgentId: "",
})
response, err := ona.Services.Agent.StartAgent(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"agentId": ""
}
```
## Request
`gitpod.v1.StartAgentRequest`
| Field | Type | Required | Description |
| ------------------ | ------------------------------------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agentId` | string | No | agent\_id identifies the agent to start. If omitted, the backend uses the configured default agent ID, or the Ona in-environment agent when no default is configured. Constraints: `ignore=1, string.uuid=true`. |
| `codeContext` | [AgentCodeContext](#type-gitpod-v1-agent-code-context) | No | |
| `name` | string | No | Constraints: `string.max_len=100`. |
| `workflowActionId` | string | No | workflow\_action\_id is an optional reference to the workflow execution action that created this agent execution. Used for tracking and event correlation. Constraints: `string.uuid=true`. |
| `mode` | [AgentMode](#enum-gitpod-v1-agent-mode) | No | mode specifies the operational mode for this agent execution If not specified, defaults to AGENT\_MODE\_EXECUTION |
| `runnerId` | string | No | runner\_id specifies a runner for this agent execution. When set, the agent execution is routed to this runner instead of the runner associated with the environment. Constraints: `ignore=1, string.uuid=true`. |
| `annotations` | map of string to string | No | annotations are key-value pairs for tracking external context (e.g., integration session IDs, GitHub issue references). Keys should follow domain/name convention (e.g., "agent-client-session/id"). |
| `sessionId` | string | No | session\_id is the ID of the session this agent execution belongs to. If empty, a new session is created implicitly. Constraints: `ignore=1, string.uuid=true`. |
| `codexSettings` | [CodexSettings](#type-gitpod-v1-codex-settings) | No | codex\_settings contains desired manual settings for the Codex app agent. |
| `turnOptions` | [TurnOptions](#type-gitpod-v1-turn-options) | No | turn\_options contains options for the initial turn. It is not persisted as durable execution state. |
## Response
`gitpod.v1.StartAgentResponse`
| Field | Type | Required | Description |
| ------------------ | ------ | -------- | -------------------------------- |
| `agentExecutionId` | string | No | Constraints: `string.uuid=true`. |
## Related types
`gitpod.v1.AgentCodeContext`
| Field | Type | Required | Description |
| --------------- | ------------------------------------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `projectId` | string | No | Constraints: `string.uuid=true`. |
| `environmentId` | string | No | Constraints: `string.uuid=true`. |
| `contextUrl` | [ContextURL](#type-gitpod-v1-agent-code-context-context-url) | No | |
| `pullRequest` | [PullRequest](#type-gitpod-v1-pull-request) | No | Pull request context - optional metadata about the PR being worked on This is populated when the agent execution is triggered by a PR workflow or when explicitly provided through the browser extension |
`gitpod.v1.AgentCodeContext.ContextURL`
| Field | Type | Required | Description |
| -------------------- | ------ | -------- | -------------------------------- |
| `url` | string | No | Constraints: `string.uri=true`. |
| `environmentClassId` | string | No | Constraints: `string.uuid=true`. |
CodexSettings contains settings consumed only by the Codex app agent.
`gitpod.v1.CodexSettings`
| Field | Type | Required | Description |
| ----------------- | -------------------------------------------------------------- | -------- | -------------------------------------- |
| `model` | [CodexOpenAIModel](#enum-gitpod-v1-codex-open-ai-model) | No | Constraints: `enum.defined_only=true`. |
| `reasoningEffort` | [CodexReasoningEffort](#enum-gitpod-v1-codex-reasoning-effort) | No | Constraints: `enum.defined_only=true`. |
| `serviceTier` | [CodexServiceTier](#enum-gitpod-v1-codex-service-tier) | No | Constraints: `enum.defined_only=true`. |
PullRequest represents pull request metadata from source control systems.
This message is used across workflow triggers, executions, and agent contexts
to maintain consistent PR information throughout the system.
`gitpod.v1.PullRequest`
| Field | Type | Required | Description |
| ------------ | ------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | string | No | Unique identifier from the source system (e.g., "123" for GitHub PR #123) |
| `title` | string | No | Pull request title |
| `fromBranch` | string | No | Source branch name (the branch being merged from) |
| `toBranch` | string | No | Target branch name (the branch being merged into) |
| `url` | string | No | Pull request URL (e.g., "[https://github.com/owner/repo/pull/123](https://github.com/owner/repo/pull/123)") |
| `author` | string | No | Author name as provided by the SCM system |
| `repository` | Repository | No | |
| `draft` | boolean | No | Whether this is a draft pull request |
| `state` | [State](#enum-gitpod-v1-pull-request-state) | No | |
| `headSha` | string | No | Current revision identity for the PR head commit. Used internally for workflow execution deduplication and excluded from customer SDKs. |
`gitpod.v1.TurnOptions`
| Field | Type | Required | Description |
| ------- | ------------------------------------------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `modes` | array of [AgentMode](#enum-gitpod-v1-agent-mode) | No | modes contains requested modes for this turn. Agents decide whether a mode remains active after the submitted turn and report durable state via AgentExecution.Status. Constraints: `repeated.max_items=4`. |
AgentMode defines the operational mode of an agent
| Value | Number | Description |
| ------------------------ | -----: | ----------------------------------------------------------------- |
| `AGENT_MODE_UNSPECIFIED` | 0 | Default execution mode - standard agent behavior |
| `AGENT_MODE_EXECUTION` | 1 | Execution mode - agent performs tasks and makes changes |
| `AGENT_MODE_PLANNING` | 2 | Planning mode - agent focuses on analysis and planning |
| `AGENT_MODE_RALPH` | 3 | Ralph mode - autonomous planning and implementation mode |
| `AGENT_MODE_SPEC` | 4 | Spec mode - planning phase followed by interactive implementation |
| `AGENT_MODE_GOAL` | 5 | Goal mode - agent treats the user input as a goal objective |
CodexOpenAIModel is the static allowlist of concrete OpenAI models that the
Codex app runtime can select through Ona's Codex picker.
| Value | Number | Description |
| ----------------------------------------- | -----: | --------------- |
| `CODEX_OPEN_AI_MODEL_UNSPECIFIED` | 0 | |
| `CODEX_OPEN_AI_MODEL_GPT_5_5` | 1 | |
| `CODEX_OPEN_AI_MODEL_GPT_5_4` | 2 | |
| `CODEX_OPEN_AI_MODEL_GPT_5_4_MINI` | 3 | **Deprecated.** |
| `CODEX_OPEN_AI_MODEL_GPT_5_3_CODEX` | 4 | **Deprecated.** |
| `CODEX_OPEN_AI_MODEL_GPT_5_3_CODEX_SPARK` | 5 | **Deprecated.** |
| `CODEX_OPEN_AI_MODEL_GPT_5_2` | 6 | **Deprecated.** |
| `CODEX_OPEN_AI_MODEL_GPT_5_6_SOL` | 7 | |
| `CODEX_OPEN_AI_MODEL_GPT_5_6_TERRA` | 8 | |
| `CODEX_OPEN_AI_MODEL_GPT_5_6_LUNA` | 9 | |
CodexReasoningEffort is the static allowlist of reasoning efforts supported
by the Codex app runtime.
| Value | Number | Description |
| ------------------------------------ | -----: | ----------- |
| `CODEX_REASONING_EFFORT_UNSPECIFIED` | 0 | |
| `CODEX_REASONING_EFFORT_LOW` | 1 | |
| `CODEX_REASONING_EFFORT_MEDIUM` | 2 | |
| `CODEX_REASONING_EFFORT_HIGH` | 3 | |
| `CODEX_REASONING_EFFORT_EXTRA_HIGH` | 4 | |
| `CODEX_REASONING_EFFORT_MAX` | 5 | |
| `CODEX_REASONING_EFFORT_ULTRA` | 6 | |
CodexServiceTier is the static allowlist of service tiers supported by the
Codex app runtime.
| Value | Number | Description |
| -------------------------------- | -----: | ----------- |
| `CODEX_SERVICE_TIER_UNSPECIFIED` | 0 | |
| `CODEX_SERVICE_TIER_FAST` | 1 | |
Current state of the pull request
| Value | Number | Description |
| ------------------- | -----: | ----------- |
| `STATE_UNSPECIFIED` | 0 | |
| `STATE_OPEN` | 1 | |
| `STATE_CLOSED` | 2 | |
| `STATE_MERGED` | 3 | |
# Stop Agent Execution
Source: https://ona.com/docs/api-reference/generated/agent/stop-agent-execution
Stops an active agent execution.
`Unary` · [`Agents`](/docs/api-reference/generated/agent/overview)
Stops an active agent execution.
Use this method to:
* Stop an agent that is currently running
* Prevent further processing or resource usage
### Examples
* Stop an agent execution by ID:
```yaml theme={null}
agentExecutionId: "6fa1a3c7-fbb7-49d1-ba56-1890dc7c4c35"
```
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AgentService/StopAgentExecution
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AgentService/StopAgentExecution" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"agentExecutionId": ""
}'
```
```python Python theme={null}
import gitpod.v1.agent_pb2 as agent_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = agent_pb2.StopAgentExecutionRequest(
agent_execution_id="",
)
response = ona.services.agent.stop_agent_execution(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { StopAgentExecutionRequestSchema } from "@gitpod/sdk/gitpod/v1/agent_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(StopAgentExecutionRequestSchema, {
agentExecutionId: "",
});
const response = await ona.services.agent.stopAgentExecution(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.StopAgentExecutionRequest{
AgentExecutionId: "",
})
response, err := ona.Services.Agent.StopAgentExecution(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"agentExecutionId": ""
}
```
## Request
`gitpod.v1.StopAgentExecutionRequest`
| Field | Type | Required | Description |
| ------------------ | ------ | -------- | -------------------------------- |
| `agentExecutionId` | string | No | Constraints: `string.uuid=true`. |
## Response
`gitpod.v1.StopAgentExecutionResponse`
This message has no fields.
# Update Prompt
Source: https://ona.com/docs/api-reference/generated/agent/update-prompt
Updates an existing prompt.
`Unary` · [`Agents`](/docs/api-reference/generated/agent/overview)
Updates an existing prompt.
Use this method to:
* Modify prompt content or metadata
* Change prompt type (template/command)
## Endpoint
```text theme={null}
POST /api/gitpod.v1.AgentService/UpdatePrompt
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.AgentService/UpdatePrompt" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"promptId": ""
}'
```
```python Python theme={null}
import gitpod.v1.agent_pb2 as agent_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = agent_pb2.UpdatePromptRequest(
prompt_id="",
)
response = ona.services.agent.update_prompt(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { UpdatePromptRequestSchema } from "@gitpod/sdk/gitpod/v1/agent_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(UpdatePromptRequestSchema, {
promptId: "",
});
const response = await ona.services.agent.updatePrompt(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.UpdatePromptRequest{
PromptId: "",
})
response, err := ona.Services.Agent.UpdatePrompt(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"promptId": ""
}
```
## Request
`gitpod.v1.UpdatePromptRequest`
| Field | Type | Required | Description |
| ---------- | ---------------------------------------------------------- | -------- | --------------------------------------------------------------- |
| `promptId` | string | No | The ID of the prompt to update Constraints: `string.uuid=true`. |
| `metadata` | [Metadata](#type-gitpod-v1-update-prompt-request-metadata) | No | Metadata updates |
| `spec` | [Spec](#type-gitpod-v1-update-prompt-request-spec) | No | Spec updates |
## Response
`gitpod.v1.UpdatePromptResponse`
| Field | Type | Required | Description |
| -------- | -------------------------------- | -------- | ----------- |
| `prompt` | [Prompt](#type-gitpod-v1-prompt) | No | |
## Related types
`gitpod.v1.Prompt`
| Field | Type | Required | Description |
| ---------- | ------------------------------------------------- | -------- | ----------- |
| `id` | string | No | |
| `metadata` | [PromptMetadata](#type-gitpod-v1-prompt-metadata) | No | |
| `spec` | [PromptSpec](#type-gitpod-v1-prompt-spec) | No | |
`gitpod.v1.PromptMetadata`
| Field | Type | Required | Description |
| ---------------- | ------------------ | -------- | -------------------------------------------------------------------------------------------------------- |
| `organizationId` | string | No | organization\_id is the ID of the organization that contains the prompt Constraints: `string.uuid=true`. |
| `name` | string | No | name is the human readable name of the prompt |
| `description` | string | No | description is a description of what the prompt does |
| `creator` | Subject | No | creator is the identity of the prompt creator |
| `createdAt` | RFC 3339 timestamp | No | |
| `updatedAt` | RFC 3339 timestamp | No | |
`gitpod.v1.PromptSpec`
| Field | Type | Required | Description |
| ------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `prompt` | string | No | prompt is the content of the prompt Constraints: `string.max_len=20000`. |
| `isTemplate` | boolean | No | is\_template indicates if this prompt is a template |
| `isCommand` | boolean | No | is\_command indicates if this prompt is a command |
| `command` | string | No | command is the unique command string within the organization Constraints: `string.max_len=50, string.pattern=^[a-zA-Z0-9_-]*$`. |
| `isSkill` | boolean | No | is\_skill indicates if this prompt is a skill (workflow instructions for agents) |
`gitpod.v1.UpdatePromptRequest.Metadata`
| Field | Type | Required | Description |
| ------------- | ------ | -------- | ------------------------------------------------------------------------------------------ |
| `name` | string | No | The name of the prompt Constraints: `string.max_len=255`. |
| `description` | string | No | A description of what the prompt does Constraints: `string.max_len=500, string.min_len=1`. |
`gitpod.v1.UpdatePromptRequest.Spec`
| Field | Type | Required | Description |
| ------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------ |
| `prompt` | string | No | The prompt content Constraints: `string.max_len=20000`. |
| `isTemplate` | boolean | No | Whether this prompt is a template |
| `isCommand` | boolean | No | Whether this prompt is a command |
| `command` | string | No | The command string (unique within organization) Constraints: `string.max_len=50, string.pattern=^[a-zA-Z0-9_-]*$`. |
| `isSkill` | boolean | No | Whether this prompt is a skill |
# Create Team Credit Allocation
Source: https://ona.com/docs/api-reference/generated/billing/create-team-credit-allocation
Creates a credit allocation (budget) for a team.
`Unary` · [`Billing`](/docs/api-reference/generated/billing/overview)
Creates a credit allocation (budget) for a team.
Allocations are soft budgets for reporting and alerting - not enforced at usage time.
Over-allocation (sum of team budgets > org grant) is allowed.
### Examples
* Create a team allocation:
```yaml theme={null}
organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047"
teamId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
creditBudget: "500"
```
### Authorization
Requires `billing:create` permission on the organization.
## Endpoint
```text theme={null}
POST /api/gitpod.v1.BillingService/CreateTeamCreditAllocation
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.BillingService/CreateTeamCreditAllocation" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"organizationId": "",
"teamId": ""
}'
```
```python Python theme={null}
import gitpod.v1.billing_pb2 as billing_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = billing_pb2.CreateTeamCreditAllocationRequest(
organization_id="",
team_id="",
)
response = ona.services.billing.create_team_credit_allocation(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { CreateTeamCreditAllocationRequestSchema } from "@gitpod/sdk/gitpod/v1/billing_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(CreateTeamCreditAllocationRequestSchema, {
organizationId: "",
teamId: "",
});
const response = await ona.services.billing.createTeamCreditAllocation(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.CreateTeamCreditAllocationRequest{
OrganizationId: "",
TeamId: "",
})
response, err := ona.Services.Billing.CreateTeamCreditAllocation(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"organizationId": "",
"teamId": ""
}
```
## Request
`gitpod.v1.CreateTeamCreditAllocationRequest`
| Field | Type | Required | Description |
| ---------------------- | --------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------- |
| `organizationId` | string | Yes | Constraints: `required=true, string.uuid=true`. |
| `teamId` | string | Yes | Constraints: `required=true, string.uuid=true`. |
| `creditBudget` | 64-bit integer string | No | credit\_budget is the allocated credit budget in whole credits. Constraints: `int64.gte=0`. |
| `costBudgetMicrounits` | 64-bit integer string | No | cost\_budget\_microunits is the BYOK cost budget in micro-units of the currency. Constraints: `int64.gt=0`. |
| `costBudgetCurrency` | [BillingCurrency](#enum-gitpod-v1-billing-currency) | No | Constraints: `enum.defined_only=true`. |
## Response
`gitpod.v1.CreateTeamCreditAllocationResponse`
| Field | Type | Required | Description |
| ------------ | ----------------------------------------------------------------------- | -------- | ----------- |
| `allocation` | [TeamCreditAllocationInfo](#type-gitpod-v1-team-credit-allocation-info) | No | |
## Related types
TeamCreditAllocationInfo represents a team's monthly budget allocation.
`gitpod.v1.TeamCreditAllocationInfo`
| Field | Type | Required | Description |
| ---------------------- | --------------------------------------------------- | -------- | -------------------------------------------------------------------------------- |
| `id` | string | No | Constraints: `string.uuid=true`. |
| `teamId` | string | No | Constraints: `string.uuid=true`. |
| `organizationId` | string | No | Constraints: `string.uuid=true`. |
| `creditBudget` | 64-bit integer string | No | credit\_budget is the allocated credit budget in whole credits. |
| `createdAt` | RFC 3339 timestamp | No | |
| `updatedAt` | RFC 3339 timestamp | No | |
| `costBudgetMicrounits` | 64-bit integer string | No | cost\_budget\_microunits is the BYOK cost budget in micro-units of the currency. |
| `costBudgetCurrency` | [BillingCurrency](#enum-gitpod-v1-billing-currency) | No | |
| Value | Number | Description |
| ------------------------------ | -----: | ----------- |
| `BILLING_CURRENCY_UNSPECIFIED` | 0 | |
| `BILLING_CURRENCY_USD` | 1 | |
| `BILLING_CURRENCY_EUR` | 2 | |
| `BILLING_CURRENCY_GBP` | 3 | |
# Delete Enterprise AI User Budget Policy
Source: https://ona.com/docs/api-reference/generated/billing/delete-enterprise-ai-user-budget-policy
Deletes the organization default or a per-user monthly budget policy.
`Unary` · [`Billing`](/docs/api-reference/generated/billing/overview)
Deletes the organization default or a per-user monthly budget policy.
### Authorization
Requires `billing:delete` permission on the organization.
## Endpoint
```text theme={null}
POST /api/gitpod.v1.BillingService/DeleteEnterpriseAIUserBudgetPolicy
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.BillingService/DeleteEnterpriseAIUserBudgetPolicy" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"mode": "ENTERPRISE_AI_USER_BUDGET_MODE_CREDITS",
"organizationId": ""
}'
```
```python Python theme={null}
import gitpod.v1.billing_pb2 as billing_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = billing_pb2.DeleteEnterpriseAIUserBudgetPolicyRequest(
organization_id="",
mode=billing_pb2.ENTERPRISE_AI_USER_BUDGET_MODE_CREDITS,
)
response = ona.services.billing.delete_enterprise_ai_user_budget_policy(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { DeleteEnterpriseAIUserBudgetPolicyRequestSchema, EnterpriseAIUserBudgetMode } from "@gitpod/sdk/gitpod/v1/billing_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(DeleteEnterpriseAIUserBudgetPolicyRequestSchema, {
organizationId: "",
mode: EnterpriseAIUserBudgetMode.CREDITS,
});
const response = await ona.services.billing.deleteEnterpriseAIUserBudgetPolicy(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.DeleteEnterpriseAIUserBudgetPolicyRequest{
OrganizationId: "",
Mode: gitpodpb.EnterpriseAIUserBudgetMode_ENTERPRISE_AI_USER_BUDGET_MODE_CREDITS,
})
response, err := ona.Services.Billing.DeleteEnterpriseAIUserBudgetPolicy(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"mode": "ENTERPRISE_AI_USER_BUDGET_MODE_CREDITS",
"organizationId": ""
}
```
## Request
`gitpod.v1.DeleteEnterpriseAIUserBudgetPolicyRequest`
| Field | Type | Required | Description |
| ---------------- | ---------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------- |
| `organizationId` | string | Yes | Constraints: `required=true, string.uuid=true`. |
| `mode` | [EnterpriseAIUserBudgetMode](#enum-gitpod-v1-enterprise-ai-user-budget-mode) | Yes | Constraints: `enum.defined_only=true, enum.not_in=0, required=true`. |
| `userId` | string | No | Constraints: `string.uuid=true`. |
## Response
`gitpod.v1.DeleteEnterpriseAIUserBudgetPolicyResponse`
This message has no fields.
## Related types
| Value | Number | Description |
| -------------------------------------------- | -----: | ----------- |
| `ENTERPRISE_AI_USER_BUDGET_MODE_UNSPECIFIED` | 0 | |
| `ENTERPRISE_AI_USER_BUDGET_MODE_CREDITS` | 1 | |
| `ENTERPRISE_AI_USER_BUDGET_MODE_BYOK` | 2 | |
# Delete Team Credit Allocation
Source: https://ona.com/docs/api-reference/generated/billing/delete-team-credit-allocation
Deletes the credit allocation for a team.
`Unary` · [`Billing`](/docs/api-reference/generated/billing/overview)
Deletes the credit allocation for a team.
### Examples
* Delete a team's allocation:
```yaml theme={null}
organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047"
teamId: "d2c94c27-3b76-4a42-b88c-95a85e392c68"
```
### Authorization
Requires `billing:delete` permission on the organization.
## Endpoint
```text theme={null}
POST /api/gitpod.v1.BillingService/DeleteTeamCreditAllocation
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.BillingService/DeleteTeamCreditAllocation" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"organizationId": "",
"teamId": ""
}'
```
```python Python theme={null}
import gitpod.v1.billing_pb2 as billing_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = billing_pb2.DeleteTeamCreditAllocationRequest(
organization_id="",
team_id="",
)
response = ona.services.billing.delete_team_credit_allocation(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { DeleteTeamCreditAllocationRequestSchema } from "@gitpod/sdk/gitpod/v1/billing_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(DeleteTeamCreditAllocationRequestSchema, {
organizationId: "",
teamId: "",
});
const response = await ona.services.billing.deleteTeamCreditAllocation(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.DeleteTeamCreditAllocationRequest{
OrganizationId: "",
TeamId: "",
})
response, err := ona.Services.Billing.DeleteTeamCreditAllocation(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"organizationId": "",
"teamId": ""
}
```
## Request
`gitpod.v1.DeleteTeamCreditAllocationRequest`
| Field | Type | Required | Description |
| ---------------- | ------ | -------- | ----------------------------------------------- |
| `organizationId` | string | Yes | Constraints: `required=true, string.uuid=true`. |
| `teamId` | string | Yes | Constraints: `required=true, string.uuid=true`. |
## Response
`gitpod.v1.DeleteTeamCreditAllocationResponse`
This message has no fields.
# Get Credit Usage Export
Source: https://ona.com/docs/api-reference/generated/billing/get-credit-usage-export
Returns a signed download URL for a CSV export of credit usage.
`Unary` · [`Billing`](/docs/api-reference/generated/billing/overview)
Returns a signed download URL for a CSV export of credit usage.
The URL points to an HTTP endpoint that streams gzip-compressed CSV and
is valid for five minutes. The download must be made by the same principal
that requested it, carrying its own bearer token. The export range may
cover up to a year.
For organizations without enterprise credit usage enabled (no billing
contract start date), the export instead contains BYOK cost usage with a
different column set, and groupBy=RESOURCE is rejected.
Use this method to:
* Export per-user daily credit usage for external reporting
* Export a per-environment and per-conversation resource breakdown
### Examples
* Export January's daily summary:
```yaml theme={null}
organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047"
dateRange:
startTime: "2024-01-01T00:00:00Z"
endTime: "2024-01-31T00:00:00Z"
groupBy: CREDIT_USAGE_EXPORT_GROUP_BY_DAILY_SUMMARY
```
### Authorization
Requires `billing:read_usage` permission on the organization.
## Endpoint
```text theme={null}
POST /api/gitpod.v1.BillingService/GetCreditUsageExport
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.BillingService/GetCreditUsageExport" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"dateRange": {
"endTime": "2026-01-01T00:00:00Z",
"startTime": "2026-01-01T00:00:00Z"
},
"organizationId": ""
}'
```
```python Python theme={null}
import gitpod.v1.billing_pb2 as billing_pb2
import gitpod.v1.usage_pb2 as usage_pb2
import google.protobuf.timestamp_pb2 as timestamp_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = billing_pb2.GetCreditUsageExportRequest(
organization_id="",
date_range=usage_pb2.DateRange(
start_time=timestamp_pb2.Timestamp(seconds=1767225600),
end_time=timestamp_pb2.Timestamp(seconds=1767225600),
),
)
response = ona.services.billing.get_credit_usage_export(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { GetCreditUsageExportRequestSchema } from "@gitpod/sdk/gitpod/v1/billing_pb";
import { timestampFromDate } from "@bufbuild/protobuf/wkt";
async function main() {
const ona = createClientFromEnv();
const request = create(GetCreditUsageExportRequestSchema, {
organizationId: "",
dateRange: {
startTime: timestampFromDate(new Date("2026-01-01T00:00:00Z")),
endTime: timestampFromDate(new Date("2026-01-01T00:00:00Z")),
},
});
const response = await ona.services.billing.getCreditUsageExport(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.GetCreditUsageExportRequest{
OrganizationId: "",
DateRange: &gitpodpb.DateRange{
StartTime: ×tamppb.Timestamp{Seconds: 1767225600},
EndTime: ×tamppb.Timestamp{Seconds: 1767225600},
},
})
response, err := ona.Services.Billing.GetCreditUsageExport(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"dateRange": {
"endTime": "2026-01-01T00:00:00Z",
"startTime": "2026-01-01T00:00:00Z"
},
"organizationId": ""
}
```
## Request
`gitpod.v1.GetCreditUsageExportRequest`
| Field | Type | Required | Description |
| ---------------- | ------------------------------------------------------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `organizationId` | string | Yes | Constraints: `required=true, string.uuid=true`. |
| `dateRange` | [DateRange](#type-gitpod-v1-date-range) | Yes | Date range to export. Both start and end dates are inclusive; time-of-day is ignored. Unlike GetCreditUsageReport, the range may cover up to a year. Constraints: `required=true`. |
| `groupBy` | [CreditUsageExportGroupBy](#enum-gitpod-v1-credit-usage-export-group-by) | No | How to group the export data. Defaults to DAILY\_SUMMARY. |
## Response
`gitpod.v1.GetCreditUsageExportResponse`
| Field | Type | Required | Description |
| ------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------- |
| `downloadUrl` | string | No | Signed download URL for the CSV export. Valid for five minutes, and only for the principal that requested it. |
## Related types
DateRange specifies a time period for queries.
`gitpod.v1.DateRange`
| Field | Type | Required | Description |
| ----------- | ------------------ | -------- | ----------------------------------------------------------------------- |
| `startTime` | RFC 3339 timestamp | Yes | Start time of the date range (inclusive). Constraints: `required=true`. |
| `endTime` | RFC 3339 timestamp | Yes | End time of the date range (exclusive). Constraints: `required=true`. |
How to group the credit usage export data.
| Value | Number | Description |
| -------------------------------------------- | -----: | --------------------------------------------- |
| `CREDIT_USAGE_EXPORT_GROUP_BY_UNSPECIFIED` | 0 | Defaults to DAILY\_SUMMARY. |
| `CREDIT_USAGE_EXPORT_GROUP_BY_DAILY_SUMMARY` | 1 | Daily summary grouped by user. |
| `CREDIT_USAGE_EXPORT_GROUP_BY_RESOURCE` | 2 | Breakdown by environment and agent execution. |
# Get Credit Usage Report
Source: https://ona.com/docs/api-reference/generated/billing/get-credit-usage-report
Returns a daily credit usage report for an enterprise organization.
`Unary` · [`Billing`](/docs/api-reference/generated/billing/overview)
Returns a daily credit usage report for an enterprise organization.
Each day reports org-wide credits by usage type, plus per-user, per-team,
per-environment, and per-conversation breakdowns (top consumers with the
remainder aggregated into an "Others" bucket) and a per-model breakdown
of intelligence usage.
Use this method to:
* Chart daily credit consumption over a date range
* Attribute credit usage to users, teams, environments, and conversations
* Restrict the report to a single user or service account
### Examples
* Get the report for January:
Both dates are inclusive and the range must not exceed 31 days.
```yaml theme={null}
organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047"
dateRange:
startTime: "2024-01-01T00:00:00Z"
endTime: "2024-01-31T00:00:00Z"
```
### Authorization
Requires `billing:read_usage` permission on the organization. A user
without it can read their own usage by setting filter.subject to their
own user identity; this self-access path is not available to service
accounts.
## Endpoint
```text theme={null}
POST /api/gitpod.v1.BillingService/GetCreditUsageReport
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.BillingService/GetCreditUsageReport" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"dateRange": {
"endTime": "2026-01-01T00:00:00Z",
"startTime": "2026-01-01T00:00:00Z"
},
"organizationId": ""
}'
```
```python Python theme={null}
import gitpod.v1.billing_pb2 as billing_pb2
import gitpod.v1.usage_pb2 as usage_pb2
import google.protobuf.timestamp_pb2 as timestamp_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = billing_pb2.GetCreditUsageReportRequest(
organization_id="",
date_range=usage_pb2.DateRange(
start_time=timestamp_pb2.Timestamp(seconds=1767225600),
end_time=timestamp_pb2.Timestamp(seconds=1767225600),
),
)
response = ona.services.billing.get_credit_usage_report(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { GetCreditUsageReportRequestSchema } from "@gitpod/sdk/gitpod/v1/billing_pb";
import { timestampFromDate } from "@bufbuild/protobuf/wkt";
async function main() {
const ona = createClientFromEnv();
const request = create(GetCreditUsageReportRequestSchema, {
organizationId: "",
dateRange: {
startTime: timestampFromDate(new Date("2026-01-01T00:00:00Z")),
endTime: timestampFromDate(new Date("2026-01-01T00:00:00Z")),
},
});
const response = await ona.services.billing.getCreditUsageReport(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.GetCreditUsageReportRequest{
OrganizationId: "",
DateRange: &gitpodpb.DateRange{
StartTime: ×tamppb.Timestamp{Seconds: 1767225600},
EndTime: ×tamppb.Timestamp{Seconds: 1767225600},
},
})
response, err := ona.Services.Billing.GetCreditUsageReport(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"dateRange": {
"endTime": "2026-01-01T00:00:00Z",
"startTime": "2026-01-01T00:00:00Z"
},
"organizationId": ""
}
```
## Request
`gitpod.v1.GetCreditUsageReportRequest`
| Field | Type | Required | Description |
| ---------------- | --------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `organizationId` | string | Yes | Constraints: `required=true, string.uuid=true`. |
| `dateRange` | [DateRange](#type-gitpod-v1-date-range) | Yes | Date range for the report. Both start and end dates are inclusive. Time-of-day is ignored; dates are truncated to midnight in the specified timezone. The range must not exceed 31 days. Constraints: `required=true`. |
| `timezone` | string | No | IANA timezone name (e.g. "America/New\_York", "Europe/Berlin") used to bucket daily usage. When empty, defaults to "UTC". |
| `filter` | [CreditUsageReportFilter](#type-gitpod-v1-credit-usage-report-filter) | No | Optional filter narrowing the returned data. When unset or empty, the response preserves the default behavior (top-N users + "Others"). See CreditUsageReportFilter for per-field response-scoping semantics. |
## Response
`gitpod.v1.GetCreditUsageReportResponse`
| Field | Type | Required | Description |
| ------------- | --------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------- |
| `updatedAt` | RFC 3339 timestamp | No | When the report data was last computed. |
| `dailyUsage` | array of [DailyCreditUsage](#type-gitpod-v1-daily-credit-usage) | No | One entry per day in the requested date range. |
| `periodStart` | RFC 3339 timestamp | No | Start of the billing period for this organization. Used by the frontend to filter out months before usage tracking began. |
## Related types
AgentExecutionCreditUsage contains a single agent execution's credit usage for a day, broken down by type.
`gitpod.v1.AgentExecutionCreditUsage`
| Field | Type | Required | Description |
| ------------------ | ---------------------- | -------- | -------------------------------------------------------- |
| `agentExecutionId` | string | No | Empty when representing the "Others" aggregation bucket. |
| `displayName` | string | No | |
| `usage` | array of CreditsByType | No | |
CreditUsageReportFilter narrows the data returned by GetCreditUsageReport.
Wrapping filters in a message (rather than adding bare fields) lets future
filters (team, environment, resource kind) be added without further breaking
changes.
`gitpod.v1.CreditUsageReportFilter`
| Field | Type | Required | Description |
| --------- | ---------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `subject` | [Subject](#type-gitpod-v1-subject) | No | Restrict the per-user breakdown to a single subject. The subject must be PRINCIPAL\_USER or PRINCIPAL\_SERVICE\_ACCOUNT and belong to the request's organization. When unset, the report returns the default top-N users + "Others" breakdown. When this field is set: - daily\_usage\[*].user\_usage contains rows only for the requested subject; no "Others" aggregation bucket is produced. - daily\_usage\[*].org\_usage, team\_usage, environment\_usage, and conversation\_usage are omitted (empty). Callers that need those sections should issue an unfiltered call. - period\_start and updated\_at remain populated. |
CreditsByType contains credits consumed for a single usage type.
`gitpod.v1.CreditsByType`
| Field | Type | Required | Description |
| ----------- | --------------------------------------- | -------- | ----------- |
| `usageType` | [UsageType](#enum-gitpod-v1-usage-type) | No | |
| `credits` | number | No | |
DailyCreditUsage contains credit usage for a single day.
`gitpod.v1.DailyCreditUsage`
| Field | Type | Required | Description |
| ------------------- | ---------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `date` | RFC 3339 timestamp | No | Start of the day (midnight in the requested timezone). |
| `orgUsage` | array of [CreditsByType](#type-gitpod-v1-credits-by-type) | No | Org-wide usage broken down by type. |
| `userUsage` | array of [UserCreditUsage](#type-gitpod-v1-user-credit-usage) | No | Per-user usage for this day (top users + "Others"). |
| `teamUsage` | array of [TeamCreditUsage](#type-gitpod-v1-team-credit-usage) | No | Per-team usage for this day (top teams + "Others"). Empty team\_id represents the "Others" aggregation bucket. |
| `environmentUsage` | array of [EnvironmentCreditUsage](#type-gitpod-v1-environment-credit-usage) | No | Per-environment usage for this day (top environments + "Others"). Empty environment\_id represents the "Others" aggregation bucket. |
| `conversationUsage` | array of [AgentExecutionCreditUsage](#type-gitpod-v1-agent-execution-credit-usage) | No | Per-agent-execution usage for this day (top conversations + "Others"). Empty agent\_execution\_id represents the "Others" aggregation bucket. |
| `usageByModel` | array of [EnterpriseAIUsageByModel](#type-gitpod-v1-enterprise-ai-usage-by-model) | No | Org-wide intelligence usage broken down by model. |
DateRange specifies a time period for queries.
`gitpod.v1.DateRange`
| Field | Type | Required | Description |
| ----------- | ------------------ | -------- | ----------------------------------------------------------------------- |
| `startTime` | RFC 3339 timestamp | Yes | Start time of the date range (inclusive). Constraints: `required=true`. |
| `endTime` | RFC 3339 timestamp | Yes | End time of the date range (exclusive). Constraints: `required=true`. |
`gitpod.v1.EnterpriseAIUsageByModel`
| Field | Type | Required | Description |
| -------------------------- | ------------------------------------- | -------- | ----------------------------------------------------------------------- |
| `model` | string | No | |
| `usage` | EnterpriseAIUsage | No | |
| `usageByTokenType` | array of EnterpriseAIUsageByTokenType | No | |
| `unpricedUsage` | EnterpriseAIUsage | No | Usage excluded from spend because no matching BYOK rate was configured. |
| `unpricedUsageByTokenType` | array of EnterpriseAIUsageByTokenType | No | |
EnvironmentCreditUsage contains a single environment's credit usage for a day, broken down by type.
`gitpod.v1.EnvironmentCreditUsage`
| Field | Type | Required | Description |
| --------------- | ---------------------- | -------- | -------------------------------------------------------- |
| `environmentId` | string | No | Empty when representing the "Others" aggregation bucket. |
| `displayName` | string | No | |
| `usage` | array of CreditsByType | No | |
`gitpod.v1.Subject`
| Field | Type | Required | Description |
| ----------- | -------------------------------------- | -------- | -------------------------------------------------------------------------------- |
| `id` | string | No | id is the UUID of the subject Constraints: `ignore=1, string.uuid=true`. |
| `principal` | [Principal](#enum-gitpod-v1-principal) | No | Principal is the principal of the subject Constraints: `enum.defined_only=true`. |
TeamCreditUsage contains a single team's credit usage for a day, broken down by type.
`gitpod.v1.TeamCreditUsage`
| Field | Type | Required | Description |
| ------------- | ---------------------- | -------- | -------------------------------------------------------- |
| `teamId` | string | No | Empty when representing the "Others" aggregation bucket. |
| `displayName` | string | No | |
| `usage` | array of CreditsByType | No | |
UserCreditUsage contains a single user's credit usage, broken down by type.
`gitpod.v1.UserCreditUsage`
| Field | Type | Required | Description |
| -------------- | --------------------------------- | -------- | -------------------------------------------------------- |
| `userId` | string | No | Empty when representing the "Others" aggregation bucket. |
| `displayName` | string | No | |
| `usage` | array of CreditsByType | No | |
| `usageByModel` | array of EnterpriseAIUsageByModel | No | Intelligence usage broken down by model. |
| Value | Number | Description |
| --------------------------- | -----: | ----------- |
| `PRINCIPAL_UNSPECIFIED` | 0 | |
| `PRINCIPAL_ACCOUNT` | 1 | |
| `PRINCIPAL_USER` | 2 | |
| `PRINCIPAL_RUNNER` | 3 | |
| `PRINCIPAL_ENVIRONMENT` | 4 | |
| `PRINCIPAL_SERVICE_ACCOUNT` | 5 | |
| `PRINCIPAL_RUNNER_MANAGER` | 6 | |
UsageType identifies the category of usage.
| Value | Number | Description |
| ------------------------ | -----: | ----------- |
| `USAGE_TYPE_UNSPECIFIED` | 0 | |
| `USAGE_TYPE_ENVIRONMENT` | 1 | |
| `USAGE_TYPE_AGENTIC` | 2 | |
# Get Cumulative Credit Usage
Source: https://ona.com/docs/api-reference/generated/billing/get-cumulative-credit-usage
Returns cumulative credit usage for an organization and its teams.
`Unary` · [`Billing`](/docs/api-reference/generated/billing/overview)
Returns cumulative credit usage for an organization and its teams.
Use this method to:
* Get the total cumulative credit consumption as of a point in time
* Get per-team cumulative usage with credit allocation (budget) comparison
* Display team credit summaries on the usage page and team detail page
* Display user budget utilization when user budgets are enabled
### Examples
* Get current cumulative usage:
```yaml theme={null}
organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047"
```
* Get cumulative usage as of a specific date:
```yaml theme={null}
organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047"
asOf: "2026-03-31T23:59:59Z"
```
### Authorization
Requires `billing:read_usage` permission on the organization.
## Endpoint
```text theme={null}
POST /api/gitpod.v1.BillingService/GetCumulativeCreditUsage
```
Send a Bearer token as described in [Authentication](/docs/api-reference#authenticate-requests). If your organization uses a custom management-plane domain, replace `https://app.ona.com` with that domain.
## Request example
```bash cURL theme={null}
export ONA_HOST=https://app.ona.com
export ONA_API_KEY=
curl --request POST \
--url "$ONA_HOST/api/gitpod.v1.BillingService/GetCumulativeCreditUsage" \
--header "Authorization: Bearer $ONA_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"organizationId": ""
}'
```
```python Python theme={null}
import gitpod.v1.billing_pb2 as billing_pb2
from ona_sdk import create_client_from_env
ona = create_client_from_env()
request = billing_pb2.GetCumulativeCreditUsageRequest(
organization_id="",
)
response = ona.services.billing.get_cumulative_credit_usage(request)
print(response)
```
```typescript TypeScript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { GetCumulativeCreditUsageRequestSchema } from "@gitpod/sdk/gitpod/v1/billing_pb";
async function main() {
const ona = createClientFromEnv();
const request = create(GetCumulativeCreditUsageRequestSchema, {
organizationId: "",
});
const response = await ona.services.billing.getCumulativeCreditUsage(request);
console.log(response);
}
main().catch(console.error);
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"connectrpc.com/connect"
"github.com/gitpod-io/gitpod-sdk-go/sdk"
gitpodpb "github.com/gitpod-io/gitpod-sdk-go/v1"
)
func main() {
ona, err := sdk.NewFromEnv()
if err != nil {
log.Fatal(err)
}
request := connect.NewRequest(&gitpodpb.GetCumulativeCreditUsageRequest{
OrganizationId: "",
})
response, err := ona.Services.Billing.GetCumulativeCreditUsage(context.Background(), request)
if err != nil {
log.Fatal(err)
}
fmt.Println(response.Msg)
}
```
```json Request body theme={null}
{
"organizationId": ""
}
```
## Request
`gitpod.v1.GetCumulativeCreditUsageRequest`
| Field | Type | Required | Description |
| ---------------- | ------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------- |
| `organizationId` | string | Yes | organization\_id is the ID of the organization to get cumulative usage for. Constraints: `required=true, string.uuid=true`. |
| `asOf` | RFC 3339 timestamp | No | as\_of is the point in time to compute cumulative usage up to. Defaults to now if not set. |
## Response
`gitpod.v1.GetCumulativeCreditUsageResponse`
| Field | Type | Required | Description |
| --------------- | ---------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `orgUsage` | [CumulativeCreditUsage](#type-gitpod-v1-cumulative-credit-usage) | No | Org-wide cumulative usage, broken down by type and total. |
| `teamUsage` | array of [TeamCumulativeCreditUsage](#type-gitpod-v1-team-cumulative-credit-usage) | No | Per-team cumulative usage with credit allocation comparison. Returns all teams (no top-N limit). |
| `unteamedUsage` | [CumulativeCreditUsage](#type-gitpod-v1-cumulative-credit-usage) | No | Usage by members not assigned to any team. |
| `periodStart` | RFC 3339 timestamp | No | Start of the cumulative calculation period. Cumulative totals are computed from this date forward. |
| `userUsage` | array of [UserCreditBudgetUsage](#type-gitpod-v1-user-credit-budget-usage) | No | Per-user month-to-date usage for every user with usage in the period. The budget fields on each entry are populated only when a monthly budget applies to that user. This list is not paginated or capped; for large organizations prefer ListEnterpriseUserCreditUsage. |
## Related types
CreditsByType contains credits consumed for a single usage type.
`gitpod.v1.CreditsByType`
| Field | Type | Required | Description |
| ----------- | --------------------------------------- | -------- | ----------- |
| `usageType` | [UsageType](#enum-gitpod-v1-usage-type) | No | |
| `credits` | number | No | |
CumulativeCreditUsage contains cumulative credit consumption totals.
`gitpod.v1.CumulativeCreditUsage`
| Field | Type | Required | Description |
| -------------- | --------------------------------------------------------- | -------- | ------------------------------------------- |
| `totalCredits` | number | No | Total credits consumed. |
| `usageByType` | array of [CreditsByType](#type-gitpod-v1-credits-by-type) | No | Credits consumed broken down by usage type. |
`gitpod.v1.EnterpriseAIUsageByModel`
| Field | Type | Required | Description |
| -------------------------- | ------------------------------------- | -------- | ----------------------------------------------------------------------- |
| `model` | string | No | |
| `usage` | EnterpriseAIUsage | No | |
| `usageByTokenType` | array of EnterpriseAIUsageByTokenType | No | |
| `unpricedUsage` | EnterpriseAIUsage | No | Usage excluded from spend because no matching BYOK rate was configured. |
| `unpricedUsageByTokenType` | array of EnterpriseAIUsageByTokenType | No | |
TeamCumulativeCreditUsage contains a team's cumulative credit usage and allocation.
`gitpod.v1.TeamCumulativeCreditUsage`
| Field | Type | Required | Description |
| -------------- | ---------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `teamId` | string | No | |
| `displayName` | string | No | |
| `usage` | [CumulativeCreditUsage](#type-gitpod-v1-cumulative-credit-usage) | No | Cumulative credit usage for this team. |
| `creditBudget` | 64-bit integer string | No | The team's credit allocation (budget) in whole credits, if set. Not set means no allocation has been configured for this team. |
`gitpod.v1.UserCreditBudgetUsage`
| Field | Type | Required | Description |
| -------------------- | --------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `userId` | string | No | |
| `displayName` | string | No | |
| `monthToDateUsage` | [CumulativeCreditUsage](#type-gitpod-v1-cumulative-credit-usage) | No | |
| `creditBudget` | 64-bit integer string | No | |
| `budgetSource` | [EnterpriseAIUserBudgetPolicySource](#enum-gitpod-v1-enterprise-ai-user-budget-policy-source) | No | Constraints: `enum.defined_only=true`. |
| `noCap` | boolean | No | |
| `utilizationPercent` | number | No | |
| `overBudget` | boolean | No | |
| `isServiceAccount` | boolean | No | True when user\_id refers to a service account rather than a human user. The dashboard uses this to mark non-human accounts in admin tables. |
| `usageByModel` | array of [EnterpriseAIUsageByModel](#type-gitpod-v1-enterprise-ai-usage-by-model) | No | Month-to-date intelligence usage broken down by model. |
| Value | Number | Description |
| ------------------------------------------------------ | -----: | ----------- |
| `ENTERPRISE_AI_USER_BUDGET_POLICY_SOURCE_UNSPECIFIED` | 0 | |
| `ENTERPRISE_AI_USER_BUDGET_POLICY_SOURCE_NONE` | 1 | |
| `ENTERPRISE_AI_USER_BUDGET_POLICY_SOURCE_ORGANIZATION` | 2 | |
| `ENTERPRISE_AI_USER_BUDGET_POLICY_SOURCE_USER` | 3 | |
UsageType identifies the category of usage.
| Value | Number | Description |
| ------------------------ | -----: | ----------- |
| `USAGE_TYPE_UNSPECIFIED` | 0 | |
| `USAGE_TYPE_ENVIRONMENT` | 1 | |
| `USAGE_TYPE_AGENTIC` | 2 | |
# Billing
Source: https://ona.com/docs/api-reference/generated/billing/overview
BillingService provides billing and subscription management functionality.
BillingService provides billing and subscription management functionality.
## Methods
Creates a credit allocation (budget) for a team.
Deletes the organization default or a per-user monthly budget policy.
Deletes the credit allocation for a team.
Returns a signed download URL for a CSV export of credit usage.
Returns a daily credit usage report for an enterprise organization.
Returns cumulative credit usage for an organization and its teams.
Returns organization-level enterprise AI usage totals for reporting.
Returns daily enterprise AI usage totals for the organization.
Gets the configured and effective monthly budget policy for a user or org.
Gets the credit allocation for a team.
Lists enterprise AI usage grouped by team.
Lists enterprise AI usage grouped by user with effective monthly budget data.
Lists per-user month-to-date credit usage with effective monthly budgets.
Sets the organization default or a per-user monthly budget policy.
Updates the credit allocation for a team.
# Migrate from SDK versions 0.x
Source: https://ona.com/docs/api-reference/sdk-migration
Migrate Python, TypeScript, and Go code from Ona SDK versions 0.x to versions 1.x.
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Upgrade the SDK package and update your code in the same change. SDK versions 1.x are not drop-in compatible with versions 0.x. The migration does not change Ona resources or invalidate personal access tokens.
If your application pins a 0.x version, migrate its code before upgrading the SDK dependency to 1.x.
The distribution names remain `gitpod-sdk`, `@gitpod/sdk`, and `github.com/gitpod-io/gitpod-sdk-go`. Imports, environment variables, request types, responses, and error types change.
Use the examples shipped in the [Python source distribution](https://pypi.org/project/gitpod-sdk/#files), [TypeScript package](https://unpkg.com/browse/@gitpod/sdk@latest/examples/), or [public Go module mirror](https://github.com/gitpod-io/gitpod-sdk-go). Do not use examples from the former language-specific SDK repositories.
## Review the breaking changes
| Concern | Versions 0.x | Versions 1.x |
| --------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------- |
| API key variable | `GITPOD_API_KEY` | `ONA_API_KEY` |
| Custom API URL | Client-specific base URL option | `ONA_BASE_URL` or a constructor option |
| Python client | `Gitpod` or `AsyncGitpod` from `gitpod` | `create_client_from_env` or `create_client` from `ona_sdk` |
| TypeScript client | Default `Gitpod` export | Named `createClientFromEnv`, `createClient`, or `OnaClient` exports |
| Go client | `gitpod.NewClient` and `option.*` | `sdk.NewFromEnv` and `sdk.*` options |
| Request and response models | JSON models | Protobuf messages and Connect clients |
| Environment operations | Service methods plus language-specific helpers | Resource clients and `Environment` handles |
| Python concurrency | Synchronous and asynchronous clients | Synchronous client |
| Runtime | Python 3.9+, browser and server/edge JavaScript runtimes, Go 1.22+ | Python 3.10+, Node.js 20+, Go 1.25+ |
| Retries | Automatic retries for selected failures | No automatic application-level retries |
| Errors | 0.x API error hierarchy | SDK workflow errors or Connect errors for direct RPCs |
## Find SDK 0.x usage
Search the application before changing dependencies:
```bash theme={null}
rg -n 'GITPOD_API_KEY|from gitpod import|AsyncGitpod|new Gitpod|gitpod.NewClient|gitpod-sdk-go/option'
```
Also inspect wrapper modules, dependency lockfiles, deployment secrets, retry configuration, and tests that mock 0.x response or error types. Keep this list as the migration checklist for the application.
## Upgrade the package
Upgrade the package and commit the resulting lockfile or module changes:
```bash theme={null}
python -m pip install --upgrade gitpod-sdk
```
```bash theme={null}
npm install @gitpod/sdk@latest
```
```bash theme={null}
go get github.com/gitpod-io/gitpod-sdk-go@latest
go mod tidy
```
Do not upgrade a production dependency before the matching code changes are ready. The new release replaces classes and types under the existing distribution names.
## Rename authentication variables
Rename `GITPOD_API_KEY` to `ONA_API_KEY` in deployment configuration, local environment files, and secret stores:
```bash theme={null}
export ONA_API_KEY=""
```
During a staged rollout, you can expose the same personal access token under both names. Remove `GITPOD_API_KEY` after every workload uses an SDK version 1.x.
For an organization with a custom management-plane domain, set the API URL explicitly:
```bash theme={null}
export ONA_BASE_URL="https:///api"
```
The default is `https://app.ona.com/api`.
## Replace client construction and environment workflows
Move environment lifecycle and environment operations to the high-level resource clients. These workflows replace manual environment-class selection, polling helpers, and command helpers used with SDK versions 0.x.
Replace `Gitpod` or `AsyncGitpod` with `create_client_from_env`:
```python theme={null}
# Before: SDK 0.x
from gitpod import Gitpod
client = Gitpod()
environments = client.environments.list()
```
```python theme={null}
# After: SDK 1.x
from ona_sdk import create_client_from_env
ona = create_client_from_env()
environments = ona.environments().list()
```
Create an environment and run a command through the returned handle:
```python theme={null}
environment = ona.environments().create(
"https://github.com/gitpod-io/template-golang-cli"
)
try:
result = environment.run_command(
command="go test ./...",
working_directory=environment.workspace_dir(),
)
print(result.stdout)
finally:
ona.environments().delete(environment.id(), force=True)
```
The Python SDK version 1.x is synchronous. In an asynchronous application, call it through a worker thread instead of importing `AsyncGitpod`:
```python theme={null}
import asyncio
environment = await asyncio.to_thread(
ona.environments().get,
"",
)
```
Replace the default `Gitpod` class with a named client factory:
```typescript theme={null}
// Before: SDK 0.x
import Gitpod from "@gitpod/sdk";
const client = new Gitpod();
const environments = client.environments.list();
```
```typescript theme={null}
// After: SDK 1.x
import { createClientFromEnv } from "@gitpod/sdk";
const ona = createClientFromEnv();
const environments = ona.environments().list();
```
Create an environment and run a command through the returned handle:
```typescript theme={null}
const environment = await ona.environments().create({
contextUrl: "https://github.com/gitpod-io/template-golang-cli",
});
try {
const result = await environment.runCommand({
command: "go test ./...",
workingDirectory: environment.workspaceDir(),
});
console.log(result.stdout);
} finally {
await ona.environments().delete(environment.id(), { force: true });
}
```
Replace the 0.x root client and `option` package with the high-level `sdk` package:
```go theme={null}
// Before: SDK 0.x
client := gitpod.NewClient(
option.WithBearerToken(os.Getenv("GITPOD_API_KEY")),
)
```
```go theme={null}
// After: SDK 1.x
ona, err := sdk.NewFromEnv()
if err != nil {
return err
}
```
Create an environment and run a command through the returned handle:
```go theme={null}
environment, err := ona.Environments().Create(ctx, sdk.CreateEnvironmentOptions{
ContextURL: "https://github.com/gitpod-io/template-golang-cli",
})
if err != nil {
return err
}
defer ona.Environments().Delete(ctx, environment.ID(), sdk.DeleteEnvironmentOptions{Force: true})
status := environment.Proto().GetStatus()
workspaceDir := status.GetDevcontainer().GetRemoteWorkspaceFolder()
if workspaceDir == "" {
workspaceDir = status.GetContent().GetContentLocationInMachine()
}
result, err := environment.RunCommand(ctx, sdk.RunCommandOptions{
Command: "go test ./...",
WorkingDirectory: workspaceDir,
})
if err != nil {
return err
}
fmt.Print(result.Stdout)
```
High-level `create` calls wait for the environment to run. `stop` waits for the environment to stop, and `delete` cleans it up. Remove 0.x polling utilities that duplicate this behavior.
## Migrate direct API calls to Connect
Use generated protobuf messages and Connect clients for API methods that the high-level workflows do not cover. Request fields now follow the public protobuf schema instead of the parameter objects from versions 0.x.
Authenticated synchronous service clients are available through `ona.services`:
```python theme={null}
from gitpod.v1.identity_pb2 import GetAuthenticatedIdentityRequest
from ona_sdk import create_client_from_env
ona = create_client_from_env()
response = ona.services.identity.get_authenticated_identity(
GetAuthenticatedIdentityRequest()
)
print(response.organization_id)
```
Generated responses are protobuf messages, not Pydantic models. Replace helpers such as `to_dict()` and `to_json()` with protobuf-aware serialization where needed.
Construct protobuf-es v2 messages with `create` and the generated request schema:
```typescript theme={null}
import { create } from "@bufbuild/protobuf";
import { createClientFromEnv } from "@gitpod/sdk";
import { GetAuthenticatedIdentityRequestSchema } from "@gitpod/sdk/gitpod/v1/identity_pb";
const ona = createClientFromEnv();
const response = await ona.services.identity.getAuthenticatedIdentity(
create(GetAuthenticatedIdentityRequestSchema),
);
console.log(response.organizationId);
```
Import message types and service descriptors from generated package subpaths. Do not construct typed protobuf messages with bare object literals.
Use the generated Connect clients under `v1/v1connect`. Configure the HTTP client with the same token used by the high-level SDK:
```go theme={null}
token := os.Getenv("ONA_API_KEY")
baseURL := os.Getenv("ONA_BASE_URL")
if baseURL == "" {
baseURL = "https://app.ona.com/api"
}
httpClient := oauth2.NewClient(ctx, oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
))
identity := v1connect.NewIdentityServiceClient(httpClient, baseURL)
response, err := identity.GetAuthenticatedIdentity(
ctx,
connect.NewRequest(&v1.GetAuthenticatedIdentityRequest{}),
)
if err != nil {
return err
}
fmt.Println(response.Msg.GetOrganizationId())
```
This example uses `connectrpc.com/connect`, `golang.org/x/oauth2`, `github.com/gitpod-io/gitpod-sdk-go/v1`, and `github.com/gitpod-io/gitpod-sdk-go/v1/v1connect`.
See the [API reference](https://ona.com/docs/api-reference) for the current public services and fields.
## Update pagination, timeouts, and errors
Replace 0.x runtime helpers with their 1.x equivalents:
* **Pagination:** High-level environment lists still fetch pages lazily. Iterate the Python generator, TypeScript async generator, or Go `iter.Seq2`. For direct RPCs, send `PaginationRequest.token` from the previous `PaginationResponse.next_token`.
* **Timeouts:** Use `timeout` in Python, an `AbortSignal` or `defaultTimeoutMs` in TypeScript, and `context.Context` deadlines in Go.
* **Errors:** Catch typed `SDKError` subclasses for high-level workflows. Direct calls use the language's Connect error type. Replace checks for 0.x types such as `APIStatusError`, `APIConnectionError`, and `gitpod.Error`.
* **Retries:** Add retries at your application boundary only for operations that are safe to repeat. Do not assume the 0.x default of two retries still applies.
## Test the migrated application
Before deploying:
1. Run the language type checker, compiler, and tests.
2. Test authentication with `ONA_API_KEY`.
3. Create, use, and delete a disposable environment.
4. Test expected error branches, timeouts, and pagination.
5. Test `ONA_BASE_URL` if the organization uses a custom domain.
6. Remove 0.x-only imports, helpers, error types, and the old `GITPOD_API_KEY` setting.
Use the [Ona SDK guide](/docs/ona/integrations/sdk) for current installation and workflow examples.
## Troubleshooting
The application still uses a 0.x import. Python code should import from `ona_sdk`, TypeScript should use named exports such as `createClientFromEnv`, and Go workflow code should import the `sdk` package.
The Python SDK version 1.x is synchronous. Run SDK calls in a worker thread with `asyncio.to_thread`, or move the SDK work to a synchronous worker process.
Build the request with the generated protobuf type for that RPC. In TypeScript, use `create(RequestSchema, fields)`. In Python and Go, instantiate the generated request message. Check the API reference because 0.x parameter names and helper types do not carry over.
Confirm that the process receives `ONA_API_KEY`, not only `GITPOD_API_KEY`. For custom domains, also confirm that `ONA_BASE_URL` uses the management-plane domain and ends in `/api`.
# Audit logs
Source: https://ona.com/docs/ona/audit-logs/overview
Audit logs provide a queryable record of all actions in your organization: who performed an operation, on which resource, and when. Use them for security monitoring, compliance reporting, and troubleshooting.
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
## Access requirements
Organization admins and members with the [Audit Log Reader](/docs/ona/organizations/organization-roles#audit-log-reader) role can access audit logs. Regular members cannot access audit logs, even for resources they own.
## Entry structure
Each entry contains:
* **Actor**: Who (user, service account, runner, or system)
* **Subject**: What resource, with its public type when one exists
* **Action**: Operation performed (e.g., "Environment created")
* **Timestamp**: When
* **Organization**: Which org
* **Kind**: The coarse event family used for querying and rendering
## What gets logged
Audit logs focus on security-relevant and human-meaningful activity. This includes approved resource lifecycle and administration changes, relevant credential activity, and security activity reported from environments.
| Category | Resources |
| -------------- | ---------------------------------------------------------------------------------------------- |
| Infrastructure | Environments, Runners, Projects, Environment Classes |
| Execution | Tasks, Services, Workflows, Agents, and their executions |
| Security | Users, Service Accounts, Tokens, Secrets, SSO configuration, and security policies |
| Organization | [Policies](/docs/ona/organizations/policies/overview), Domain Verification, Custom Domains, Billing |
| Integrations | SCM/LLM integrations and Prompts |
Routine phase, status, heartbeat, reconciliation, bookkeeping, duplicate, and cascade activity is omitted. Not every database update produces an audit entry.
New entries use one of these kinds:
* `AUDIT_LOG_ENTRY_KIND_RESOURCE_CHANGE`: resource lifecycle and administration
* `AUDIT_LOG_ENTRY_KIND_CREDENTIAL_ACCESS`: relevant credential issuance, retrieval, replacement, or propagation
* `AUDIT_LOG_ENTRY_KIND_ENVIRONMENT_VETO`: activity reported by Veto from inside an environment
Veto Exec enforcement entries are in preview and only appear for organizations where this preview is enabled.
Veto Exec events appear as environment audit entries when enabled. Blocked and audited executions both use `AUDIT_LOG_ENTRY_KIND_ENVIRONMENT_VETO`; the action and `details.vetoExec.action` distinguish the outcome.
The action includes the kernel-resolved filename and full executable digest when reported:
* Filename and digest: `Veto Exec blocked: ()`
* Filename only: `Veto Exec blocked: `
* Digest only: `Veto Exec blocked: `
* Neither: `Veto Exec blocked an executable`
Audited events use `audited` in place of `blocked`. The entry timestamp records when Ona received the event. Veto Exec details include the reported event data except `process.cmdline`, which is omitted because it may contain credentials or other sensitive data.
**Actor types:**
| Type | Description |
| --------------------------- | ------------------------- |
| `PRINCIPAL_USER` | Human users |
| `PRINCIPAL_SERVICE_ACCOUNT` | Service accounts |
| `PRINCIPAL_RUNNER` | Runner infrastructure |
| `PRINCIPAL_ENVIRONMENT` | Environment processes |
| `PRINCIPAL_RUNNER_MANAGER` | Runner management systems |
| `PRINCIPAL_ACCOUNT` | Account-level operations |
## Querying audit logs
### CLI
The `ona` CLI (pre-installed in all environments) is the simplest way to query audit logs.
```bash theme={null}
# View recent entries (default: 100)
ona audit-logs
# Specify limit
ona audit-logs --limit=500
```
**Filter by actor:**
```bash theme={null}
# By user ID
ona audit-logs --actor-id="d2c94c27-3b76-4a42-b88c-95a85e392c68"
# By actor type
ona audit-logs --actor-principal="user"
ona audit-logs --actor-principal="service_account"
```
**Filter by subject:**
```bash theme={null}
# By resource ID
ona audit-logs --subject-id="01951d94-d6ac-7edf-9021-a044cfd1908f"
# By resource type
ona audit-logs --subject-type="environment"
ona audit-logs --subject-type="project"
```
**Filter by time range:**
```bash theme={null}
# Logs from a specific date onward
ona audit-logs --from="2025-01-01T00:00:00Z"
# Logs within a date range
ona audit-logs --from="2025-01-01T00:00:00Z" --to="2025-01-31T23:59:59Z"
```
**Combine filters:**
```bash theme={null}
ona audit-logs --subject-type="environment" --actor-principal="user" --limit=500
```
**Export formats:**
```bash theme={null}
# JSON
ona audit-logs --format=json --limit=1000 > audit-logs.json
# YAML
ona audit-logs --format=yaml --limit=1000 > audit-logs.yaml
```
**Example output:**
```
SUBJECT ID SUBJECT TYPE ACTOR ID ACTOR PRINCIPAL ACTION CREATED AT
01951d94-d6ac-7edf-9021-a044cfd1908f RESOURCE_TYPE_ENVIRONMENT d2c94c27-3b76-4a42-b88c-95a85e392c68 PRINCIPAL_USER started environment 2025-02-21T12:10:05Z
0194f5dd-01ca-75f4-a200-74381ed43f86 RESOURCE_TYPE_PROJECT d2c94c27-3b76-4a42-b88c-95a85e392c68 PRINCIPAL_USER Project created 2025-02-21T11:45:22Z
```
### API
For programmatic access and SIEM integration, use the REST API.
```bash theme={null}
export GITPOD_API_KEY="your-personal-access-token"
```
The examples use `https://app.gitpod.io`. If your organization uses a custom domain, replace this origin with your organization's dashboard domain.
**Basic request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.EventService/ListAuditLogs \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{"pagination": {"pageSize": 100}}'
```
**Filter by actor:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.EventService/ListAuditLogs \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"filter": {
"actorIds": ["d2c94c27-3b76-4a42-b88c-95a85e392c68"],
"actorPrincipals": ["PRINCIPAL_USER"]
},
"pagination": {"pageSize": 100}
}'
```
**Filter by subject:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.EventService/ListAuditLogs \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"filter": {
"subjectTypes": ["RESOURCE_TYPE_ENVIRONMENT", "RESOURCE_TYPE_PROJECT"]
},
"pagination": {"pageSize": 100}
}'
```
**Pagination:**
```bash theme={null}
# First request - save token
curl https://app.gitpod.io/api/gitpod.v1.EventService/ListAuditLogs \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{"pagination": {"pageSize": 100}}' \
| jq -r '.pagination.nextToken' > next_token.txt
# Subsequent request - use token
curl https://app.gitpod.io/api/gitpod.v1.EventService/ListAuditLogs \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d "{\"pagination\": {\"pageSize\": 100, \"token\": \"$(cat next_token.txt)\"}}"
```
**Response format:**
```json theme={null}
{
"entries": [
{
"id": "01951d94-d6ac-7edf-9021-a044cfd1908f",
"actorId": "d2c94c27-3b76-4a42-b88c-95a85e392c68",
"actorPrincipal": "PRINCIPAL_USER",
"subjectId": "0194f5dd-01ca-75f4-a200-74381ed43f86",
"subjectType": "RESOURCE_TYPE_ENVIRONMENT",
"action": "started environment",
"kind": "AUDIT_LOG_ENTRY_KIND_RESOURCE_CHANGE",
"createdAt": "2025-02-21T12:10:05Z"
}
],
"pagination": {
"nextToken": "eyJpZCI6IjAxOTUxZDk0LWQ2YWMtN2VkZi05MDIxLWEwNDRjZmQxOTA4ZiJ9"
}
}
```
`ListAuditLogs` returns summary fields and the kind. Historical Veto Exec entries retain their deprecated blocked or audited kind. Other historical entries with a missing or unrecognized stored kind are returned as `AUDIT_LOG_ENTRY_KIND_UNSPECIFIED`; they are not removed from pagination. An entry whose internal subject has no public resource-type mapping uses `RESOURCE_TYPE_UNSPECIFIED` while retaining its subject ID. The response does not include the `details` payload.
**Retrieve one entry with typed details:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.EventService/GetAuditLog \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{"auditLogEntryId": "01951d94-d6ac-7edf-9021-a044cfd1908f"}'
```
For a Veto Exec entry, the response contains a `vetoExec` details case:
```json theme={null}
{
"entry": {
"id": "01951d94-d6ac-7edf-9021-a044cfd1908f",
"actorId": "0193e2f2-d0b5-7d52-87eb-235deadaf625",
"actorPrincipal": "PRINCIPAL_ENVIRONMENT",
"subjectId": "0193e2f2-d0b5-7d52-87eb-235deadaf625",
"subjectType": "RESOURCE_TYPE_ENVIRONMENT",
"action": "Veto Exec blocked: /usr/bin/curl (sha256:abcdef)",
"createdAt": "2026-07-17T12:00:02Z",
"kind": "AUDIT_LOG_ENTRY_KIND_ENVIRONMENT_VETO"
},
"details": {
"vetoExec": {
"environmentId": "0193e2f2-d0b5-7d52-87eb-235deadaf625",
"executable": "sha256:abcdef",
"filename": "/usr/bin/curl",
"action": "KERNEL_CONTROLS_ACTION_BLOCK",
"process": {
"pid": 1234,
"tid": 1234,
"name": "curl",
"startedAt": "2026-07-17T12:00:00Z",
"ppid": 1000,
"pgid": 1000,
"sid": 1000
},
"timestamp": "2026-07-17T12:00:01Z"
}
}
}
```
The `details` field is optional. Clients must handle entries without details and unknown future detail types.
## Real-time event monitoring
For real-time notifications instead of historical queries, use the **WatchEvents API**. This streaming endpoint pushes events as they occur. Use it for dashboards, automation triggers, and live monitoring.
### Key differences
| Feature | ListAuditLogs API | WatchEvents API |
| ------------ | ----------------------------------------- | ----------------------------------- |
| **Purpose** | Historical analysis | Real-time monitoring |
| **Access** | Organization Admins and Audit Log Readers | Users with read access to resources |
| **Data** | Full audit trail with actor info | Resource changes only |
| **Format** | Paginated queries | Streaming events |
| **Use Case** | Compliance, security review | Dashboards, automation |
### WatchEvents with Python
Install the official SDK:
```bash theme={null}
pip install gitpod-sdk
```
The `GITPOD_API_KEY` environment variable should contain your [Personal Access Token](/docs/ona/integrations/personal-access-token). You only receive events for resources you have read access to.
**Watch organization events:**
```python theme={null}
import os
from gitpod import Gitpod
client = Gitpod(bearer_token=os.environ.get("GITPOD_API_KEY"))
# Stream organization-wide events (projects, runners, environments)
for event in client.events.watch(organization=True):
print(f"{event.operation} on {event.resource_type}: {event.resource_id}")
```
**Watch environment-specific events:**
```python theme={null}
# Stream events for a specific environment (includes tasks, services)
for event in client.events.watch(environment_id="01951d94-d6ac-7edf-9021-a044cfd1908f"):
print(f"Environment event: {event.operation} on {event.resource_type}")
```
**Async usage:**
```python theme={null}
import asyncio
from gitpod import AsyncGitpod
client = AsyncGitpod(bearer_token=os.environ.get("GITPOD_API_KEY"))
async def watch_events():
async for event in await client.events.watch(organization=True):
print(f"{event.operation} on {event.resource_type}")
asyncio.run(watch_events())
```
### Event operations
* `RESOURCE_OPERATION_CREATE` - Resource created
* `RESOURCE_OPERATION_UPDATE` - Resource modified
* `RESOURCE_OPERATION_UPDATE_STATUS` - Status changed only
* `RESOURCE_OPERATION_DELETE` - Resource deleted
### Other languages
For languages without an official SDK, use gRPC/Connect-compatible clients:
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.EventService/WatchEvents`
**Headers:**
* `Content-Type: application/json`
* `Accept: application/jsonl`
* `Authorization: Bearer YOUR_API_KEY`
**Request body (organization scope):**
```json theme={null}
{"organization": true}
```
**Request body (environment scope):**
```json theme={null}
{"environmentId": "01951d94-d6ac-7edf-9021-a044cfd1908f"}
```
See the [WatchEvents API reference](https://ona.com/docs/api-reference/resources/events/methods/watch/) for details.
## Common use cases
### Security monitoring
```bash theme={null}
# Monitor secret operations
ona audit-logs --subject-type="secret" --subject-type="user_secret" --subject-type="organization_secret"
# Track SSO changes
ona audit-logs --subject-type="sso_config"
# Review token management
ona audit-logs --subject-type="personal_access_token"
```
### Compliance reporting
```bash theme={null}
# Export user actions
ona audit-logs --actor-principal="user" --format=json --limit=10000 > user-actions.json
# Track group changes
ona audit-logs --subject-type="group" --format=json > group-changes.json
```
### Troubleshooting
```bash theme={null}
# Recent environment changes
ona audit-logs --subject-type="environment" --limit=500
# Project configuration updates
ona audit-logs --subject-type="project" --actor-principal="user" --limit=500
# Workflow execution history
ona audit-logs --subject-type="workflow_execution" --limit=500
```
### Resource lifecycle tracking
```bash theme={null}
# Runner lifecycle
ona audit-logs --subject-type="runner" --limit=500
# Environment creation/deletion patterns
ona audit-logs --subject-type="environment" --limit=1000
```
## Best practices
**Regular monitoring**
* Export audit logs periodically to external storage for long-term retention
* Integrate with your SIEM for centralized security monitoring
* Establish baseline patterns and investigate anomalies
**Access control**
* Grant Organization Admin role only to users who need audit log access
* Use dedicated service accounts for automated log collection
* Rotate Personal Access Tokens regularly
**Filtering & analysis**
* Prioritize monitoring security-sensitive resource types
* Combine multiple filter criteria to narrow results
* Export to JSON/YAML for integration with analysis tools
## Limitations
* **Retention**: Audit logs are retained according to your organization's data retention policy
* **Rate limits**: API requests subject to standard rate limiting
* **Filter limits**: Maximum 25 values per filter type per request
* **Pagination**: Maximum 100 entries per page
# Best practices
Source: https://ona.com/docs/ona/best-practices
Best practices for using Ona environments, agents, and guardrails effectively in your development workflow.
Ona works out of the box, but it gets better as you configure it. This page walks through best practices in the order most teams adopt them, from writing your first prompt to automating recurring work.
Start with the basics and add more as your workflow matures.
## Write effective prompts
Include a goal, context, constraints, and success criteria. The more precise the prompt, the fewer corrections you need.
A good prompt has four parts:
1. **Goal**: What are you trying to change or build?
2. **Context**: Which files, docs, errors, or examples matter?
3. **Constraints**: What conventions, patterns, or boundaries to follow?
4. **Done when**: What should be true when the task is complete?
Example:
```text theme={null}
Goal: Add rate limiting to the /api/upload endpoint.
Context: See src/middleware/rateLimit.ts for the existing rate limiter
used on /api/auth. The upload endpoint is in src/routes/upload.ts.
Constraints: Use the same express-rate-limit library and configuration
pattern as the auth endpoint. Limit to 10 requests per minute per user.
Done when: The rate limiter is applied, a 429 response is returned when
the limit is exceeded, and the existing upload tests still pass.
```
For simple tasks, goal and context are enough. For anything larger, all four parts help Ona stay scoped.
### Be explicit
Ona performs best with explicit instructions, to the point of over-specification. Clear instructions increase the duration of autonomous work.
| Not great | Good |
| --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| add a new database entity foo | add a database entity foo for the backend which has a name, description and magic value. Users will search for the magic value, but name and desc are only shown. The magic value cannot be changed and is a number from 1 to 100. |
| add a new endpoint to our backend that allows users to get all of their purchases | Take a look at purchase.go. This file contains the definition for an endpoint that returns a single purchase by ID. Please note how authorization is done and how the tests in purchase\_test.go look - these are in line with our best practices. Add a new endpoint (GET /purchases) in the same file to get all of a user's purchases following the same authorization and testing best practices. |
| explain the codebase | Analyze this codebase and explain its general structure, architecture, and key components. What are the most important things a developer should know to get started? Include information about the tech stack, main directories, entry points, and any critical patterns or conventions used. |
| the sidebar height changes when sessions start | Understand how: • we currently keep a stable height for sidebar entries despite font weight changes • the progress counter pill changes the height of the sidebar item • we could avoid that height change in line with existing patterns.
Implement that fix. |
### Give Ona context
Ona understands intent, but it cannot read minds. Give it the context it needs.
| Method | How |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| **URLs** | Point Ona at documentation, API references, or design specs. It reads web pages directly. |
| **Screenshots** | [Attach images](/docs/ona/agents/image-attachments) by dropping them into the prompt box, using the paperclip button, or pasting from clipboard. |
| **File references** | Type `@` followed by at least 3 characters to search for files in your environment. |
| **Shell commands** | `!pwd` runs a command directly. The output becomes part of the agent's context. |
| **TODOs** | Steer the plan at any point: `Add a todo item to review and simplify your code` |
***
## Plan before building
For anything non-trivial, plan first. The cheapest way is **Plan mode**. Ona writes a `spec.md` you approve before any code is written.
Skipping the planning step is the single most common reason agent runs go off the rails. The longer the task, the more planning pays off.
### Use Plan mode
Plan mode adds a structured planning phase to a session. Ona asks clarifying questions, gathers requirements, writes a `spec.md`, and waits for your approval before writing any code.
1. In the session input or on the home screen, open the mode dropdown next to the send button and switch from **Agent** to **Plan**.
2. Describe the task. Ona asks follow-up questions as clickable multiple-choice options. Pick a choice, type a custom answer, or skip.
3. When Ona has enough context, it writes a `spec.md` with the full implementation plan.
4. Review the spec, then click **Build** in the next-steps prompt (or press `Cmd+Enter`) to start implementation against that plan.
Use Plan mode whenever the task spans more than one or two files, touches an unfamiliar part of the codebase, or has design ambiguity. For trivial edits, stay in Agent mode.
### Explore-plan-build for ad-hoc work
When you don't want a full spec but still want planning rigor, the explore-plan-build pattern works well:
1. **Explore:** Have Ona understand the system. *"Examine the authentication flow, including failure modes, security features, database connections, and audit logging. Give me a report of your findings."*
2. **Plan:** Design the change. *"We need to add audit logs to every login attempt. Ensure this doesn't impact failure rates and maintains compatibility with all SSO providers. Design a change that achieves this."*
3. **Build:** *"Implement it."* Ona already has the context and plan.
Ask Ona to write the design to a markdown file, then iterate on it in VS Code. Whenever you update the file, tell Ona to incorporate your changes. This creates a collaborative design loop where you maintain control while using Ona's capabilities.
For larger changes, ask Ona to reflect on its work after building: *"Review and critique your changes. How can you simplify things?"*
***
## Teach agents your codebase
Put durable guidance in AGENTS.md and devcontainer.json. Once a prompting pattern works, stop repeating it manually.
### Write an AGENTS.md
[AGENTS.md](https://agents.md/) is a readme for agents. Ona pulls this file into context for every session, making it an ideal place for:
* Common commands (how to test, rebuild generated code)
* Key files and parts of the system
* Code style guide locations
* Branch naming conventions
Keep it short and concise. You can refer to other files and Ona will read them when necessary. Here's an example from our own repo:
```markdown title="AGENTS.md" theme={null}
## System Architecture
For architectural understanding, refer to the .llm/ directory which contains
a high-level overview, entity glossary, and tech stack documentation.
## Feature work
- use feature branches from main for pushing work following this naming pattern:
- [2-3 initials from git config user.name]/[numeric-part-of-issue-ID]-[2-3 word shorthand]
- should not be more than 24 characters total
IMPORTANT: Always run git config user.name first to get the actual name
## Commit messages
- Follow Conventional Commits: [scope]:
- Types: feat, fix, build, chore, ci, docs, style, refactor, perf, test
## Go Conventions
- Accept interfaces, return concrete types
- Always wrap errors with fmt.Errorf and %w
- Every Ent query must use .Select() to fetch only needed columns
## Code generation
- ALWAYS use leeway scripts to generate code, e.g. `leeway run api/def:generate`
instead of running `buf generate` directly.
```
Agents follow direct, explicit instructions. Use all-caps *IMPORTANT* and *ALWAYS* sparingly to emphasize rules that must not be missed. See [Teach agents your codebase](/docs/ona/agents-md) for the full guide.
### Tools, tasks, and services
[`devcontainer.json`](/docs/ona/configuration/devcontainer/overview) describes the tools needed to work on a codebase. Developers and agents share this setup. Use [Microsoft Dev Container images](https://containers.dev/templates) and align tool versions with the CI pipeline.
`.ona/config.yaml` extends it with [tasks and services](/docs/ona/configuration/tasks-and-services/overview) that automate setup and recurring tasks. Agents can use these tasks and services and add their own, such as serving previews.
***
## Extend with integrations
Connect Linear, Slack, and your SCM at the organization level. Use MCP for everything else.
Ona has first-class integrations that connect at the organization level, with no MCP configuration or API keys required. Set them up under **Organization Settings > Integrations**.
| Integration | What it enables |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
| [**Linear**](/docs/ona/integrations/configure-linear) | Create/update issues, search tickets, link code changes. Powers templates like [10x engineer](https://ona.com/templates). |
| **Slack** | Notifications, standup updates, weekly digests, direct interaction from channels. |
| **GitHub / GitLab / Bitbucket** | Code checkout, pull requests, CI log access. Connect under **Organization Settings > Integrations**. |
For tools beyond first-class integrations, Ona supports [stdio MCP servers](https://modelcontextprotocol.io/docs/learn/architecture#transport-layer) configured in `.ona/mcp-config.json`. See the configuration guides for [Atlassian (Jira)](/docs/ona/integrations/configure-atlassian), [Sentry](/docs/ona/integrations/configure-sentry), and [Notion](/docs/ona/integrations/configure-notion).
User and organization secrets provide secure means to store API keys, as compared to committing them to the repository.
### Add a "Build with Ona" badge
Add a badge to your repository README to give contributors a one-click link to open the project in an Ona environment.

```markdown theme={null}
[](https://app.ona.com/#)
```
See the [README button](/docs/ona/integrations/readme-button) guide for the full snippet and an HTML version.
***
## Encode expertise in skills
Once a workflow becomes repeatable, turn it into a skill. Skills are organization-wide prompts the agent applies proactively.
[Skills](https://app.ona.com/settings/agent-skills) encode how your team operates. The agent discovers and applies them proactively, and they can optionally be made available as slash commands. Use them to raise pull requests, review code, and write documentation.
Built-in slash commands:
* `/clear` resets the session (asks for confirmation)
* `/model` opens the Codex model picker in active Codex conversations
* `/goal` toggles Codex goal mode in active Codex conversations when organization policy and current capabilities allow it
* `/fast` toggles Codex fast mode in active Codex conversations when the selected model, configured LLM integration, and organization policy allow it
* `/skills` lists available skills (available to org admins)
* `/support-bundle` produces a support bundle for when Ona doesn't work as intended
### Capture your best reviewers
Capture the review style of your best reviewers by analyzing their last 30 days of PR reviews, identifying patterns, and transforming those insights into a `/review-like-[name]` skill. See the [Encode a reviewer's style](/docs/ona/workflows#encode-a-reviewers-style) workflow.
See [Organization-level skills](/docs/ona/skills) for how to create skills (including [example skills we use at Ona](/docs/ona/skills#example-skills-we-use-at-ona)), and [AGENTS.md skills](/docs/ona/agents-md#skills-for-repository-specific-workflows) for repository-specific workflows.
***
## Ship code effectively
Be precise about what you want changed. Point to existing patterns instead of specifying every detail.
The most common pitfall is under-specification. Instead of *"fix the frontend tests"*, be precise: *"Fix the flaky frontend tests for the login page where the button selectors aren't being found correctly."*
The key pattern is learning from existing code: *"Add a test case to the agent tests that verifies the out-of-token failure mode. Understand the existing test cases and add one that's highly consistent."*
### Raising the pull request
Encode your team's PR standards in a [`/create-pr`](/docs/ona/skills#example-skills-we-use-at-ona) skill. Type `/create-pr` and Ona commits to an appropriately named branch, links to the relevant issue, generates a description, and follows all team conventions. See the [Raise a pull request](/docs/ona/workflows#raise-a-pull-request) workflow.
### Adapt your review process
A [`/code-review`](/docs/ona/skills#example-skills-we-use-at-ona) skill automates the mechanical parts: gathering diffs, checking conventions, and posting inline comments.
* **Draft PRs as a pressure valve**: Push early and often. Let reviewers peek into work-in-progress while agents continue iterating.
* **Tests matter more than implementation details**: With AI-generated code, tests define the expected behavior. Prioritize reviewing them.
* **Consistency through context**: Maintain coding guidelines as markdown files in your repositories. The agent handles mechanical consistency checks, freeing reviewers for architectural decisions.
### Treat documentation as code
A [`/technical-writing`](/docs/ona/skills#example-skills-we-use-at-ona) skill guides writers so everyone writes in one voice. Make the skill interactive instead of trying to one-shot the result. Encode your team's critical terminology (e.g. "Dev Container" not "devcontainer", "environments" not "workspaces").
***
## Automate recurring work
Start from a template. Connect integrations. Let background agents handle the work you do every day.
[Automations](/docs/ona/automations/configure-automations) run on schedules or triggers (new issues, pull requests, webhooks) so work gets done even when you're not at your desk. Each automation runs in its own isolated environment with full access to your codebase, tools, and integrations.
The fastest way to start is from a [template](https://ona.com/templates):
* **10x engineer**: Daily, picks your top Linear issue, implements it, runs tests, and opens a draft PR
* **Scan recent commits for bugs**: Proposes minimal fixes in a draft PR
* **Sentry error triage and fix**: Traces errors to source, applies a fix, and opens a PR
* **CVE mitigation and dependency updates**: Updates dependencies, runs tests, and opens a PR
* **Draft weekly release notes**: Groups the week's merged PRs by category with summaries
Each automation can run multiple agents concurrently across your projects. Configure concurrency limits and max actions per batch to control scope. Monitor status, success rates, and run history from the Automations dashboard.
### Ask Ona
"Ask Ona" can become as natural as "Google it" for your team. New developers can use Ona as an onboarding companion instead of consuming senior engineers' time. Teams can also generate [weekly digests](/docs/ona/workflows#generate-a-weekly-digest) and [measure agent adoption](/docs/ona/workflows#measure-agent-adoption).
***
## Optimize your flow
Run agents in parallel, one environment per task. Let the agent handle 90% of the work; finish the last 10% yourself.
### Go parallel
Press Cmd+Enter (Ctrl+Enter on non-Mac) to start an agent and stay on the Home page, firing off tasks one after another. Each task gets its own environment: completely isolated, no file conflicts.
### 90% agent, 10% human
Don't make fine adjustments through the agent. Sometimes opening a text editor and moving that line is faster.
* Use the agent for the bulk of the changes. Start with precise instructions and encourage questions.
* Finish and refine in VS Code web. The diff view is useful for initial review.
* Start an adjustment (e.g. a refactoring) and ask Ona to understand and complete the changes.
### Progressive engagement
The complexity of the change determines how deep you go:
* **Simple changes**: The session summary is enough to raise a PR directly.
* **Medium changes**: VS Code Web for manual edits combined with agents.
* **Deep work**: A desktop IDE, only when establishing a new pattern manually.
### Preview before you ship
Ona will try to provide a preview when it thinks that's helpful. You can also ask explicitly:
```text theme={null}
Provide a preview for the front end changes you just made.
```
The generated URL can be shared with colleagues. Previews are useful for mobile development (open the link on your phone) and for [before vs after comparisons](/docs/ona/workflows#compare-before-vs-after).
### Commit early, commit often
Git acts as a checkpoint system. Commit any changes that are functional, even if incomplete. Ona can rewrite history or squash commits later. The larger the change, the more often you want Ona to commit.
Be explicit: *"Commit all your changes, once"* or *"Keep committing whenever you think is a good time"* or *"Do not commit or push."*
### Stay in control
Join the session at any time to course correct. Click Stop or press ESC, then send a corrective message. Use `/clear` to reset the session while keeping the environment (files, database state, networking).
**On mobile**: Open [app.ona.com](https://app.ona.com) on your phone. Agents are autonomous, so mobile works well for checking in, reviewing outcomes, and firing off new tasks.
### Set guardrails
* **[Command deny list](/docs/ona/command-deny-list)**: Block risky commands across the organization. For example, deny `aws *` to prevent accidental production operations.
* **Agent policies**: In **Settings → Organization → Agents**, control which agent families members can use and disable Codex goal mode when persistent objectives are not appropriate for your organization.
* **[Executable deny list](/docs/ona/organizations/policies/executable-deny-list)**: Block binaries by content hash at the kernel level. Cannot be bypassed by renaming or symlinking. Powered by [Veto](https://ona.com/stories/introducing-veto-security-for-the-next-era-of-software).
***
## Common mistakes
* **Overloading prompts with durable rules.** Move them into [AGENTS.md](/docs/ona/agents-md) or a [skill](/docs/ona/skills).
* **Not telling the agent how to verify its work.** Include build, test, and lint commands in AGENTS.md.
* **Skipping planning on complex tasks.** For multi-step changes, switch to [Plan mode](#plan-before-building) and approve the spec before building.
* **Using one environment for multiple tasks.** Strive for [one environment per task](#go-parallel).
* **Micro-adjusting through the agent.** Open VS Code and move that line yourself. Follow the [90/10 rule](#90-agent-10-human).
* **Automating before the workflow is reliable.** Turn it into a [skill](#encode-expertise-in-skills) first, then an [automation](#automate-recurring-work).
* **Watching the agent step by step.** Start a task, work on something else, come back to review. Use [parallel tasks](#go-parallel).
# AI cost usage API
Source: https://ona.com/docs/ona/billing/cost-usage-api
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
The AI cost usage API exposes the BYOK (bring-your-own-key) spend data behind **Settings → Cost & Budgets**: organization totals, per-team and per-user attribution with budgets, and a daily time series. Use it to export AI spend to finance tools, find your top spenders, or track budget utilization.
All four endpoints report BYOK token spend only. Usage from Ona Intelligence (Ona-managed models) is not included, and the `credits` field is never populated. For budget concepts, see [User budgets](/docs/ona/billing/user-budgets).
## Ona Intelligence or BYOK? Choose the right API
Ona meters AI usage one of two ways, depending on how your organization is set up. The two models have separate APIs:
| Your setup | How usage is metered | Use |
| ----------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------- |
| **BYOK** (your own provider keys) | Spend in your billing currency, via BYOK rate cards | **This API** |
| **Ona Intelligence** (Ona-managed models) | Credits (OCUs) consumed as you use environments and AI | **[Ona Intelligence usage API](/docs/ona/billing/ona-intelligence-usage-api)** |
**Not sure which applies to you?** Open **Settings → Cost & Budgets**: if usage is shown as **spend in a currency** (USD, EUR, or GBP), you are on BYOK (use this API); if it is shown in **credits**, you are using Ona Intelligence (use the Ona Intelligence usage API). The APIs also tell you directly: these cost endpoints return empty usage for organizations on Ona Intelligence, and the Ona Intelligence usage API returns `FAILED_PRECONDITION` with `enterprise credit usage is not enabled` for BYOK-only organizations.
## Authentication
All endpoints accept a Bearer token: a [personal access token](/docs/ona/integrations/personal-access-token) (acts as you) or a [service account token](/docs/ona/organizations/service-accounts) (owned by the organization, recommended for ongoing automation).
```bash theme={null}
export GITPOD_API_KEY="your-token"
```
Organization admins and members with the [Billing Viewer](/docs/ona/organizations/organization-roles#billing-viewer) role can read all usage. Other members can read their own usage by setting `filter.subject` to themselves on the per-user endpoints.
## Request format
Every endpoint is a POST with a JSON body:
```text theme={null}
POST https://app.gitpod.io/api/gitpod.v1.BillingService/
```
| Parameter | Required | Description |
| ---------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `organizationId` | Yes | Your organization ID. |
| `dateRange` | Yes | `startTime` and `endTime` as RFC-3339 timestamps. Both dates are inclusive and the range must not exceed 31 days. Time-of-day is ignored; dates are truncated to midnight in the request timezone. |
| `timezone` | No | IANA timezone name used to bucket usage (for example `Europe/London`). Defaults to `UTC`. |
| `pagination` | List endpoints | `pageSize` and `token` for paging through results. |
Responses follow three conventions:
* Costs are reported as `costMicrounits`: millionths of the billing `currency` unit, so `"84500000"` with `BILLING_CURRENCY_USD` is \$84.50. Currencies are `BILLING_CURRENCY_USD`, `BILLING_CURRENCY_EUR`, or `BILLING_CURRENCY_GBP`.
* 64-bit integer fields (costs, token counts, limits) are returned as JSON strings, per protobuf JSON encoding. Parse them as integers.
* `calculatedAt` is the time through which usage has been calculated. Usage after that timestamp may still be processing, and fields with zero values are omitted from responses.
## Organization usage summary
Returns organization-wide spend and token counts for the date range, the monthly budget when one applies, and a per-model breakdown. Usage that no configured BYOK rate matched is reported separately as `unpricedUsage`.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.BillingService/GetEnterpriseAIUsageSummary`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.BillingService/GetEnterpriseAIUsageSummary \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"organizationId": "",
"dateRange": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-30T00:00:00Z"}
}'
```
**Response:**
```json theme={null}
{
"calculatedAt": "2026-07-09T11:58:02Z",
"usage": {
"costMicrounits": "84500000",
"currency": "BILLING_CURRENCY_USD",
"tokens": {
"inputTokens": "48200000",
"outputTokens": "6100000",
"cacheTokens": "310400000",
"totalTokens": "364700000"
}
},
"budget": {
"source": "ENTERPRISE_AI_USAGE_BUDGET_SOURCE_ORGANIZATION",
"monthlyCostLimitMicrounits": "250000000",
"currency": "BILLING_CURRENCY_USD",
"monthToDateUsage": {
"costMicrounits": "84500000",
"currency": "BILLING_CURRENCY_USD"
},
"utilizationPercent": 33.8
},
"usageByModel": [
{
"model": "gpt-5.6-terra",
"usage": {
"costMicrounits": "61200000",
"currency": "BILLING_CURRENCY_USD",
"tokens": { "inputTokens": "31500000", "outputTokens": "4400000", "cacheTokens": "228000000", "totalTokens": "263900000" }
},
"usageByTokenType": [
{ "tokenType": "BYOK_RATE_CARD_TOKEN_TYPE_INPUT", "usage": { "costMicrounits": "18900000", "currency": "BILLING_CURRENCY_USD" } },
{ "tokenType": "BYOK_RATE_CARD_TOKEN_TYPE_OUTPUT", "usage": { "costMicrounits": "26400000", "currency": "BILLING_CURRENCY_USD" } },
{ "tokenType": "BYOK_RATE_CARD_TOKEN_TYPE_CACHE_READ", "usage": { "costMicrounits": "15900000", "currency": "BILLING_CURRENCY_USD" } }
]
}
]
}
```
`budget` is unset when no monthly budget applies to the organization. Token types are `BYOK_RATE_CARD_TOKEN_TYPE_INPUT`, `BYOK_RATE_CARD_TOKEN_TYPE_OUTPUT`, `BYOK_RATE_CARD_TOKEN_TYPE_CACHE_READ`, and `BYOK_RATE_CARD_TOKEN_TYPE_CACHE_WRITE`.
## Per-team usage
Returns spend per team, with each team's monthly budget when one applies. Filter to specific teams with `filter.teamIds` (up to 100).
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.BillingService/ListEnterpriseAITeamUsage`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.BillingService/ListEnterpriseAITeamUsage \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"organizationId": "",
"dateRange": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-30T00:00:00Z"},
"pagination": {"pageSize": 50}
}'
```
**Response:**
```json theme={null}
{
"pagination": {},
"calculatedAt": "2026-07-09T11:58:02Z",
"teamUsage": [
{
"teamId": "d2c94c27-3b76-4a42-b88c-95a85e392c68",
"displayName": "Platform",
"usage": {
"costMicrounits": "31800000",
"currency": "BILLING_CURRENCY_USD",
"tokens": { "inputTokens": "18400000", "outputTokens": "2300000", "cacheTokens": "119000000", "totalTokens": "139700000" }
},
"budget": {
"source": "ENTERPRISE_AI_USAGE_BUDGET_SOURCE_TEAM",
"monthlyCostLimitMicrounits": "50000000",
"currency": "BILLING_CURRENCY_USD",
"utilizationPercent": 63.6
}
}
]
}
```
## Per-user usage
Returns spend for each user and service account with attributed usage, including each subject's effective monthly budget. Usage not attributed to a user or service account is excluded, so the sum across subjects can be less than the organization totals.
Budget fields (`monthToDateUsage`, `utilizationPercent`, `overBudget`) are computed from usage inside the requested date range measured against the monthly limit. Send a range that starts on the first day of the month for true month-to-date figures.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.BillingService/ListEnterpriseAIUserUsage`
**Request** (top spenders first):
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.BillingService/ListEnterpriseAIUserUsage \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"organizationId": "",
"dateRange": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-30T00:00:00Z"},
"sort": {"field": "SORT_FIELD_USAGE", "order": "SORT_ORDER_DESC"},
"pagination": {"pageSize": 50}
}'
```
**Response:**
```json theme={null}
{
"pagination": {},
"totalCount": 24,
"calculatedAt": "2026-07-09T11:58:02Z",
"userUsage": [
{
"userId": "d2c94c27-3b76-4a42-b88c-95a85e392c68",
"displayName": "Ada Lovelace",
"monthToDateUsage": {
"costMicrounits": "9400000",
"currency": "BILLING_CURRENCY_USD",
"tokens": { "inputTokens": "5200000", "outputTokens": "700000", "cacheTokens": "34100000", "totalTokens": "40000000" }
},
"monthlyCostLimitMicrounits": "10000000",
"currency": "BILLING_CURRENCY_USD",
"budgetSource": "ENTERPRISE_AI_USER_BUDGET_POLICY_SOURCE_ORGANIZATION",
"utilizationPercent": 94,
"overBudget": false,
"isServiceAccount": false
}
]
}
```
Sort fields: `SORT_FIELD_USAGE` (default, spend), `SORT_FIELD_DISPLAY_NAME`, `SORT_FIELD_BUDGET`, `SORT_FIELD_BUDGET_USED`. Subjects without a budget sort last on the budget fields. `noCap` is true for subjects explicitly exempted from budget limits.
To restrict the list to one user or service account:
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.BillingService/ListEnterpriseAIUserUsage \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"organizationId": "",
"dateRange": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-30T00:00:00Z"},
"filter": {"subject": {"id": "", "principal": "PRINCIPAL_USER"}}
}'
```
## Daily time series
Returns one entry per day with spend totals and per-user, per-team, and per-model breakdowns. Per-user entries cover the top spenders, with the rest grouped into an "Others" bucket (empty `userId`).
When `filter.subject` is set, the response contains only that subject's usage: daily totals and the team breakdown are omitted, and the model breakdown covers the subject only.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.BillingService/GetEnterpriseAIUsageTimeSeries`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.BillingService/GetEnterpriseAIUsageTimeSeries \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"organizationId": "",
"dateRange": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-07T00:00:00Z"},
"timezone": "Europe/London"
}'
```
**Response:**
```json theme={null}
{
"calculatedAt": "2026-07-09T11:58:02Z",
"dailyUsage": [
{
"date": "2026-06-01T00:00:00Z",
"usage": {
"costMicrounits": "2900000",
"currency": "BILLING_CURRENCY_USD",
"tokens": { "inputTokens": "1600000", "outputTokens": "210000", "cacheTokens": "10400000", "totalTokens": "12210000" }
},
"userUsage": [
{ "userId": "d2c94c27-3b76-4a42-b88c-95a85e392c68", "displayName": "Ada Lovelace", "usage": { "costMicrounits": "1200000", "currency": "BILLING_CURRENCY_USD" } },
{ "userId": "", "displayName": "Others", "usage": { "costMicrounits": "1700000", "currency": "BILLING_CURRENCY_USD" } }
],
"teamUsage": [
{ "teamId": "b0e12f6c-4c67-429d-a4a6-d9838b5da047", "displayName": "Platform", "usage": { "costMicrounits": "1100000", "currency": "BILLING_CURRENCY_USD" } }
],
"usageByModel": [
{ "model": "gpt-5.6-terra", "usage": { "costMicrounits": "2100000", "currency": "BILLING_CURRENCY_USD" } }
]
}
]
}
```
# Ona Intelligence usage API
Source: https://ona.com/docs/ona/billing/ona-intelligence-usage-api
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
The Ona Intelligence usage API exposes the credit consumption data behind **Settings → Cost & Budgets**: daily usage broken down by type and by user, team, environment, and conversation; cumulative period totals with team allocations and per-user budgets; and a CSV export. Use it to export usage to finance tools, attribute spend across teams, or track budget utilization.
## Ona Intelligence or BYOK? Choose the right API
Ona meters AI usage one of two ways, depending on how your organization is set up. The two models have separate APIs:
| Your setup | How usage is metered | Use |
| ----------------------------------------- | ------------------------------------------------------ | ---------------------------------------------------- |
| **Ona Intelligence** (Ona-managed models) | Credits (OCUs) consumed as you use environments and AI | **This API** |
| **BYOK** (your own provider keys) | Spend in your billing currency, via BYOK rate cards | **[AI cost usage API](/docs/ona/billing/cost-usage-api)** |
**Not sure which applies to you?** Open **Settings → Cost & Budgets**: if usage is shown in **credits**, you are using Ona Intelligence (use this API); if it is shown as **spend in a currency** (USD, EUR, or GBP), you are on BYOK (use the cost usage API). The APIs also tell you directly: this API returns `FAILED_PRECONDITION` with `enterprise credit usage is not enabled` for BYOK-only organizations, and the cost endpoints return empty usage for organizations on Ona Intelligence.
## Authentication
All endpoints accept a Bearer token: a [personal access token](/docs/ona/integrations/personal-access-token) (acts as you) or a [service account token](/docs/ona/organizations/service-accounts) (owned by the organization, recommended for ongoing automation).
```bash theme={null}
export GITPOD_API_KEY="your-token"
```
Organization admins and members with the [Billing Viewer](/docs/ona/organizations/organization-roles#billing-viewer) role can read all usage. Other members can read their own usage on the report endpoint by setting `filter.subject` to their own user identity (this self-access path is for user tokens, not service accounts).
## Request format
Every endpoint is a POST with a JSON body:
```text theme={null}
POST https://app.gitpod.io/api/gitpod.v1.BillingService/
```
| Parameter | Required | Description |
| ---------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `organizationId` | Yes | Your organization ID. |
| `dateRange` | Report, export | `startTime` and `endTime` as RFC-3339 timestamps. Both dates are inclusive; time-of-day is ignored. The report is capped at 31 days; the export may cover up to a year. |
| `asOf` | Cumulative, list | Point in time to compute month-to-date usage up to. Defaults to now. |
| `timezone` | No | IANA timezone name (for example `Europe/London`) used to bucket daily usage. Defaults to `UTC`. |
| `pagination` | List | `pageSize` and `token` for paging. |
Response conventions:
* Credits are floating-point values (for example `12.5`). Budgets (`creditBudget`) are whole credits.
* `usageType` is `USAGE_TYPE_ENVIRONMENT` (environment runtime) or `USAGE_TYPE_AGENTIC` (agent activity).
* Token counts are returned as JSON strings, per protobuf JSON encoding.
* Fields at their default value are omitted. `creditBudget`, `utilizationPercent`, and `overBudget` appear on a user only when a budget applies, `overBudget` and `isServiceAccount` only when true, and an unset budget or zero usage leaves the field out entirely.
* `periodStart` marks the start of the billing period; usage before it is excluded.
## Daily usage report
Returns one entry per day: org-wide credits by usage type, plus per-user, per-team, per-environment, and per-conversation breakdowns (top consumers with the rest grouped into an "Others" bucket), and a per-model breakdown of agent usage.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.BillingService/GetCreditUsageReport`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.BillingService/GetCreditUsageReport \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"organizationId": "",
"dateRange": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-30T00:00:00Z"}
}'
```
**Response:**
```json theme={null}
{
"updatedAt": "2026-07-09T12:00:00Z",
"periodStart": "2026-01-01T00:00:00Z",
"dailyUsage": [
{
"date": "2026-06-01T00:00:00Z",
"orgUsage": [
{ "usageType": "USAGE_TYPE_ENVIRONMENT", "credits": 41.5 },
{ "usageType": "USAGE_TYPE_AGENTIC", "credits": 918.25 }
],
"userUsage": [
{ "userId": "d2c94c27-3b76-4a42-b88c-95a85e392c68", "displayName": "Ada Lovelace", "usage": [{ "usageType": "USAGE_TYPE_AGENTIC", "credits": 930.49 }] },
{ "userId": "", "displayName": "Others", "usage": [{ "usageType": "USAGE_TYPE_ENVIRONMENT", "credits": 33.0 }] }
],
"teamUsage": [
{ "teamId": "b0e12f6c-4c67-429d-a4a6-d9838b5da047", "displayName": "Platform", "usage": [{ "usageType": "USAGE_TYPE_AGENTIC", "credits": 622.31 }] }
],
"environmentUsage": [
{ "environmentId": "0191e4b2-6b3c-7973-a78b-68dc4a6da6b2", "displayName": "my-service", "usage": [{ "usageType": "USAGE_TYPE_ENVIRONMENT", "credits": 22.4 }] }
],
"conversationUsage": [
{ "agentExecutionId": "019ee14b-2596-771d-82d2-ef9d3d16465d", "displayName": "Add pagination to the users table", "usage": [{ "usageType": "USAGE_TYPE_AGENTIC", "credits": 231.87 }] }
],
"usageByModel": [
{
"model": "gpt-5.6-terra",
"usage": {
"credits": 930.49,
"tokens": { "inputTokens": "166562", "outputTokens": "898901", "cacheTokens": "154015590", "totalTokens": "155081053" }
},
"usageByTokenType": [
{ "tokenType": "BYOK_RATE_CARD_TOKEN_TYPE_CACHE_READ", "usage": { "credits": 892.86, "tokens": { "cacheTokens": "148810014", "totalTokens": "148810014" } } },
{ "tokenType": "BYOK_RATE_CARD_TOKEN_TYPE_OUTPUT", "usage": { "credits": 5.39, "tokens": { "outputTokens": "898901", "totalTokens": "898901" } } }
]
}
]
}
]
}
```
An empty `userId` (or `teamId`, `environmentId`, `agentExecutionId`) marks the "Others" bucket. Each `userUsage` entry also carries a `usageByModel` breakdown with the same shape as the day-level one shown here; `teamUsage`, `environmentUsage`, and `conversationUsage` do not. Token types (`BYOK_RATE_CARD_TOKEN_TYPE_INPUT`, `_OUTPUT`, `_CACHE_READ`, `_CACHE_WRITE`) apply to both Ona Intelligence and BYOK usage.
To restrict the report to one subject, set `filter.subject`:
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.BillingService/GetCreditUsageReport \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"organizationId": "",
"dateRange": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-30T00:00:00Z"},
"filter": {"subject": {"id": "", "principal": "PRINCIPAL_USER"}}
}'
```
When `filter.subject` is set, each day's `userUsage` contains only that subject (no "Others" bucket), and the org, team, environment, and conversation breakdowns are omitted.
## Cumulative period usage
Returns period-to-date totals for the organization, each team (with its credit allocation), members not on any team, and per-user month-to-date usage with budgets.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.BillingService/GetCumulativeCreditUsage`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.BillingService/GetCumulativeCreditUsage \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{"organizationId": ""}'
```
**Response:**
```json theme={null}
{
"periodStart": "2026-01-01T00:00:00Z",
"orgUsage": {
"totalCredits": 1840.75,
"usageByType": [
{ "usageType": "USAGE_TYPE_ENVIRONMENT", "credits": 1290.5 },
{ "usageType": "USAGE_TYPE_AGENTIC", "credits": 550.25 }
]
},
"teamUsage": [
{
"teamId": "b0e12f6c-4c67-429d-a4a6-d9838b5da047",
"displayName": "Platform",
"usage": { "totalCredits": 620.0, "usageByType": [{ "usageType": "USAGE_TYPE_AGENTIC", "credits": 240.0 }] },
"creditBudget": "1000"
}
],
"unteamedUsage": { "totalCredits": 90.0 },
"userUsage": [
{
"userId": "d2c94c27-3b76-4a42-b88c-95a85e392c68",
"displayName": "Ada Lovelace",
"monthToDateUsage": {
"totalCredits": 120.5,
"usageByType": [{ "usageType": "USAGE_TYPE_AGENTIC", "credits": 120.5 }]
},
"creditBudget": "150",
"budgetSource": "ENTERPRISE_AI_USER_BUDGET_POLICY_SOURCE_ORGANIZATION",
"utilizationPercent": 80.3,
"usageByModel": [
{ "model": "gpt-5.6-terra", "usage": { "credits": 120.5, "tokens": { "inputTokens": "103422", "outputTokens": "63100", "cacheTokens": "35707859", "totalTokens": "35874381" } } }
]
}
]
}
```
`teamUsage` returns all teams (no top-N limit). The `userUsage` list is not paginated or capped; for large organizations prefer the paginated list endpoint below. Each user carries a `usageByModel` breakdown; budget fields appear only when a monthly budget applies (`overBudget` only when the user is over it), and `noCap` is `true` for users exempted from limits.
## Per-user usage list
Returns per-user month-to-date usage with budgets, paginated. Ordered by total credits descending by default so the highest spenders appear first.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.BillingService/ListEnterpriseUserCreditUsage`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.BillingService/ListEnterpriseUserCreditUsage \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"organizationId": "",
"sort": {"field": "SORT_FIELD_USAGE", "order": "SORT_ORDER_DESC"},
"pagination": {"pageSize": 50}
}'
```
**Response:**
```json theme={null}
{
"totalCount": 24,
"pagination": { "nextToken": "d2c94c27-3b76-4a42-b88c-95a85e392c68" },
"userUsage": [
{
"userId": "d2c94c27-3b76-4a42-b88c-95a85e392c68",
"displayName": "Ada Lovelace",
"monthToDateUsage": {
"totalCredits": 1320.37,
"usageByType": [
{ "usageType": "USAGE_TYPE_ENVIRONMENT", "credits": 177.78 },
{ "usageType": "USAGE_TYPE_AGENTIC", "credits": 1142.59 }
]
},
"creditBudget": "500",
"budgetSource": "ENTERPRISE_AI_USER_BUDGET_POLICY_SOURCE_USER",
"utilizationPercent": 264.07,
"overBudget": true,
"usageByModel": [
{ "model": "gpt-5.6-terra", "usage": { "credits": 1142.59, "tokens": { "inputTokens": "166562", "outputTokens": "898901", "cacheTokens": "154015590", "totalTokens": "155081053" } } }
]
}
]
}
```
The page token (`nextToken`) is the last user's ID. `budgetSource` is `ENTERPRISE_AI_USER_BUDGET_POLICY_SOURCE_ORGANIZATION`, `_USER`, or `_NONE`. Sort fields: `SORT_FIELD_USAGE` (default, total credits), `SORT_FIELD_DISPLAY_NAME`, `SORT_FIELD_BUDGET`, `SORT_FIELD_BUDGET_USED`. The default usage ordering paginates over any number of users. The other three sorts compute the order in memory and are limited to organizations with at most 10,000 users; beyond that, use `SORT_FIELD_USAGE`. Because month-to-date figures are recomputed per request, hold `asOf` stable across a paginated walk to keep page tokens valid.
## CSV export
Returns a short-lived, signed download URL for a gzip-compressed CSV. The download must be made by the same principal that requested it, carrying its own bearer token.
**Endpoint:** `POST https://app.gitpod.io/api/gitpod.v1.BillingService/GetCreditUsageExport`
**Request:**
```bash theme={null}
curl https://app.gitpod.io/api/gitpod.v1.BillingService/GetCreditUsageExport \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $GITPOD_API_KEY" \
-d '{
"organizationId": "",
"dateRange": {"startTime": "2026-06-01T00:00:00Z", "endTime": "2026-06-30T00:00:00Z"},
"groupBy": "CREDIT_USAGE_EXPORT_GROUP_BY_DAILY_SUMMARY"
}'
```
**Response:**
```json theme={null}
{
"downloadUrl": "https://app.gitpod.io/billing/credit-usage-export/"
}
```
Then download within five minutes, sending your token:
```bash theme={null}
curl -L -H "Authorization: Bearer $GITPOD_API_KEY" "$DOWNLOAD_URL" | gunzip > credit-usage.csv
```
`groupBy` is `CREDIT_USAGE_EXPORT_GROUP_BY_DAILY_SUMMARY` (per-user daily summary, the default) or `CREDIT_USAGE_EXPORT_GROUP_BY_RESOURCE` (per-environment and per-conversation breakdown).
# Billing
Source: https://ona.com/docs/ona/billing/overview
Manage billing for Core Ona Cloud organizations.
This page covers self-serve billing for **Core** organizations using Ona Cloud. New self-serve organizations start on Core. All payments are processed securely by Stripe. Ona never sees your card details.
Enterprise organizations use a separate billing model. In the dashboard, **Settings → Billing** does not show self-serve billing controls for Enterprise tier organizations. For enterprise billing changes, contact your account representative.
Manage billing at **Settings → Billing**.
## Access requirements
Organization members can view Core billing details. Members with the [Billing Viewer](/docs/ona/organizations/organization-roles#billing-viewer) role can also view organization usage reports.
Only organization admins can change subscriptions, payment methods, credit top-ups, and automatic top-up settings.
## What this page covers
Use this page if you need to set up or manage Core billing:
* sign up for Core
* manage your Core subscription
* buy or automatically top up Ona Cloud credits
* handle failed payments or cancellation
For how usage is measured and how credits are consumed, continue to [Cost & Budgets](/docs/ona/billing/usage).
## Coupon codes
If you have a coupon or credit code, enter it on the billing page **before** signing up for Core. The coupon field appears during the Core signup flow at **Settings → Billing**.
## Core subscription
Core provides enhanced features and monthly credits. See [Cost & Budgets](/docs/ona/billing/usage) for how credits are consumed.
**To sign up:** Go to **Settings → Billing**, select Core, choose your monthly credit allocation, and enter payment details.
If you connect Codex to your ChatGPT account, OpenAI manages that ChatGPT plan. Ona billing still covers your Ona subscription, top-ups, and environment usage.
| Credits | Behavior |
| ------------------ | ---------------------------- |
| Monthly allocation | Reset at each billing period |
| Unused credits | Don't roll over |
| Top-up credits | Valid for up to one year |
You cannot change your Core plan variant after subscribing. To change, cancel and resubscribe with a different allocation.
## Credit top-up
Purchase additional credits at **Settings → Billing** → **Top-up**. Top-up credits are available immediately and valid for up to one year.
## Automatic credit top-up
Avoid running out of credits by enabling automatic top-ups. When your balance drops below 20 OCUs, Ona charges your default payment method and adds credits to your account.
**To enable:** Go to **Settings → Billing**, toggle **Enable auto top-up**, and select a top-up amount. A cooldown between top-ups prevents duplicate charges.
Auto top-up requires [Core plan](https://ona.com/pricing) or higher.
## Failed payments
You have **7 days** to resolve failed payments before your account is locked.
To fix: **Settings → Billing** → **Access Stripe Portal** → update payment method.
After the grace period:
* Your account is locked. You cannot start new environments until payment is resolved.
* Remaining Core credits are forfeited
* You can resubscribe at any time to restore access
## Cancellation
1. Navigate to **Settings > Billing**
2. Click **Manage** under your current plan
3. Click **Cancel plan** and confirm
Your subscription remains active until the end of the current billing period. After it expires, you cannot start new environments until you resubscribe.
## Stripe portal
Access your Stripe portal from **Settings → Billing** → **Access Stripe Portal** to:
* Update payment methods and billing address
* Add tax IDs (VAT, etc.)
* Download invoices and receipts
## Enterprise
These billing controls do not apply to Enterprise tier organizations. For enterprise billing changes, [contact sales](https://ona.com/contact/sales) or work with your account representative.
## Next steps
* [Cost & Budgets](/docs/ona/billing/usage) - Understand credit consumption
# Cost & Budgets
Source: https://ona.com/docs/ona/billing/usage
Understand usage and OCU billing for Core Ona Cloud organizations.
This page covers usage for **Core** organizations using Ona Cloud.
Enterprise organizations use a separate usage view and billing model. In Enterprise, usage is billed in credits rather than OCUs, and **Settings → Cost & Budgets** opens the enterprise view instead of the OCU view described here. See [User budgets](/docs/ona/billing/user-budgets) for per-user budgeting in Enterprise.
An **OCU (Ona Compute Unit)** measures resource consumption for Core plans. Your subscription balance is consumed in OCUs as you use environments and AI features.
## Access requirements
Organization admins and members with the [Billing Viewer](/docs/ona/organizations/organization-roles#billing-viewer) role can view **Settings → Cost & Budgets**. Billing Viewers can read usage data, but cannot add credits, change budgets, or update billing settings.
## Consumption rates
### Environments
OCUs are consumed while environments are running, based on size:
| Environment | Resources | Rate |
| --------------- | ------------------- | ----------- |
| Standard | 4 vCPUs / 16GB RAM | 1 OCU/hour |
| GPU-accelerated | 16 vCPUs / 64GB RAM | 7 OCUs/hour |
### Agentic tasks
Approximate OCU consumption for AI tasks:
| Task | OCUs |
| -------------------------------- | ---- |
| Explain a small codebase | 1 |
| Explain a large codebase | 3 |
| Create a new web app | 4 |
| Add a feature to medium codebase | 8 |
### Codex with a connected ChatGPT plan
If you [connect Codex to your ChatGPT account](/docs/ona/integrations/configure-codex), Codex model requests use your ChatGPT plan instead of Ona-managed model credits. Ona does not charge OCUs for that Codex model usage.
The environment still consumes OCUs while it is running. OpenAI manages ChatGPT-side rate limits and usage limits.
## Tracking your usage
To see how your organization is spending credits, go to **Settings → Cost & Budgets**. The Cost & Budgets page gives you a clear picture of your credit consumption over the last 7 or 30 days.
At the top, a credit summary shows your total balance, how many credits you've used, and how many are still available. Below that, a daily consumption chart breaks down your spending over time so you can spot trends or unexpected spikes.
If your credits are running low, a banner appears with an estimate of how many days you have left at your current pace so you can top up or adjust your usage before you hit zero.
Enterprise organizations can query this data programmatically with the [Ona Intelligence usage API](/docs/ona/billing/ona-intelligence-usage-api), or the [AI cost usage API](/docs/ona/billing/cost-usage-api) for organizations that bring their own provider keys (BYOK).
## Credit expiration
* **Core subscription credits** renew monthly as long as your subscription is active. They do not roll over.
* **Top-up credits** are valid for up to 1 year while you have an active subscription. Without an active subscription, top-up credits expire when the subscription ends.
* **Usage order**: Subscription credits are consumed first, then top-up credits. Bonus/gift credits are used last and typically have a longer expiration.
## Running low on credits?
* [Enable auto top-up](/docs/ona/billing/overview#automatic-credit-top-up) to add credits automatically when your balance is low
* [Top up credits](/docs/ona/billing/overview#credit-top-up) for a one-time purchase
* [Review Core subscription options](/docs/ona/billing/overview#core-subscription) for more monthly credits
## Next steps
* [Billing overview](/docs/ona/billing/overview) - Manage subscriptions and payments
* [Organizations overview](/docs/ona/organizations/overview) - Understand where usage is owned and administered
# User budgets
Source: https://ona.com/docs/ona/billing/user-budgets
Set monthly usage budgets for individual users in Enterprise organizations.
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
User budgets give every member of your organization a monthly allowance for environment and AI usage. Admins see each user's spend against their budget on the **Cost & Budgets** page, and users see their own utilization while they work.
Budgets are **soft**: they exist for reporting and visibility and are **not enforced** at usage time. A user who exceeds their budget can keep creating environments and running agents. To attribute and budget usage by team instead, see [Teams](/docs/ona/organizations/teams).
## Budget types
| Budget type | Applies to | Unit |
| ------------------ | -------------------------------------------------------- | ------------------------------------------- |
| Credit budget | Environment usage and AI usage are billed in Ona credits | Credits per month |
| Cost budget (BYOK) | Model usage billed through your own provider keys | Amount per month in your rate card currency |
Organizations with credit billing manage credit budgets in the **User credit usage** section of the Cost & Budgets page. Organizations that bring their own keys manage cost budgets in the **User AI usage** section.
Budgets reset at the start of each calendar month. Changing a budget applies going forward and does not change historical usage or budget history.
## Access requirements
Organization admins can set, change, and remove budgets. Members with the [Billing Viewer](/docs/ona/organizations/organization-roles#billing-viewer) role can see usage and budgets but cannot change them.
## Set a default budget for all users
The default budget applies to every user who does not have an individual override.
1. Go to **Settings → Cost & Budgets**
2. Open the user usage section
3. In the default budget row, click **Set budget**
4. Enter the monthly amount and save
When you change the default and some users have individual overrides, check **Apply to all users** to remove those overrides at the same time.
## Set a budget for one user
An individual budget overrides the organization default for that user.
1. Go to **Settings → Cost & Budgets**
2. Open the user usage section
3. In the user's row, click the budget value, or **Set budget** if none is set
4. Enter the monthly amount and save
To remove an individual override, open the same dialog and click **Remove override**. The user falls back to the organization default.
## Track utilization
Each row on the Cost & Budgets page shows the user's month-to-date spend, their effective budget, and the percentage used. Users over 100% are highlighted. You can sort the table by budget or budget used to find the heaviest consumers.
Users see their own budget utilization in the chat input while working with the agent, as a percentage of their monthly budget.
CSV exports of credit usage include each user's budget, so you can report on utilization outside Ona. Click **Export CSV** on the Cost & Budgets page.
## API access
Query usage, per-team and per-user attribution, and budget utilization programmatically. Use the [Ona Intelligence usage API](/docs/ona/billing/ona-intelligence-usage-api) if your organization is billed in credits, or the [AI cost usage API](/docs/ona/billing/cost-usage-api) if you bring your own provider keys (BYOK). Each page opens with a short guide to tell which applies to you.
## FAQ
Nothing is blocked. Budgets are soft limits: the user's row is highlighted as over budget on the Cost & Budgets page and their own indicator shows usage above 100%, but they can continue to create environments and use AI features. Use the Cost & Budgets page to follow up with heavy consumers.
No. Budgets are a fixed monthly allowance. Utilization starts at zero at the beginning of each calendar month.
Yes. Service accounts appear in the user usage table alongside members, and you can set a budget on a service account's row the same way.
They are independent views of the same usage. [Team budgets](/docs/ona/organizations/teams#per-team-credit-budgets) aggregate usage per team, while user budgets track each individual. Both are soft limits.
# Command deny list
Source: https://ona.com/docs/ona/command-deny-list
Block specific commands from being executed by agents.
Block specific commands from being executed by agents. Use deny lists to prevent dangerous operations, enforce security policies, and maintain compliance. This is part of [Guardrails](/docs/ona/guardrails/overview).
## How it works
1. A user provides input to an agent
2. Agent decides to execute a command
3. System checks command against deny list
4. Command is executed (if allowed) or blocked with error message
### Pattern matching
| Pattern | Effect |
| ----------- | ------------------------------------------------ |
| `shutdown` | Blocks exactly "shutdown" |
| `shutdown*` | Blocks "shutdown", "shutdown -h", "shutdown now" |
| `rm *` | Blocks all `rm` commands with arguments |
**Slash commands** (`/clear`, `/support-bundle`) are not blocked by deny lists. They are converted to prompts before reaching the agent. **Bash commands** (prefixed with `!`) are subject to deny list filtering.
## Configuration
Go to [Settings → Agents → Policies](https://app.ona.com/settings/agent-policies). Only administrators can access.
1. Add patterns to **Command Deny List** (one per line)
2. Save changes
Changes apply to new agent sessions. Existing sessions must be restarted.
### Example patterns
```
# Block package management
apt *
yum *
dnf *
# Block cloud provider CLIs
aws *
gcloud *
```
## Effect on users
When blocked, users see:
```
command execution prohibited: command matches deny pattern: rm *. Do not attempt to retry this command as it is blocked by security policy
```
* **Manual commands unaffected**: Users can still run commands directly in terminal
* **Agent only**: Only agent execution is restricted
* **No retries**: Agent is instructed not to retry blocked commands
## Security considerations
**Protects against:**
* Accidental destructive commands
* Malicious prompt injection
* Compliance violations
* Resource abuse
**Does not protect against:**
* Direct user commands in terminal
* Application-level actions
* Slash commands (cannot be blocked via deny lists)
For kernel-level binary blocking that applies to all processes (not only the agent), see the [executable deny list](/docs/ona/organizations/policies/executable-deny-list).
## Best practices
* Start with broad patterns (`aws *` instead of listing variants)
* Test in a non-production environment first
* Document why patterns were added
* Review and update periodically
## Testing
1. Create a new environment
2. Ask the agent to run a blocked command
3. Verify the error message appears
## Getting help
Enterprise customers can contact your account representative.
# OpenID Connect (OIDC)
Source: https://ona.com/docs/ona/configuration/oidc
Access cloud providers and third-party services from Ona environments using OIDC tokens, without static credentials.
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Ona issues OIDC tokens that environments, users, and service accounts can exchange for short-lived credentials from cloud providers and third-party services. This eliminates static secrets, API keys, and long-lived credentials.
OIDC tokens work with both Ona Cloud and self-hosted runners.
## Enable V3 tokens
V3 tokens are the current token format. They include flat, structured claims per principal type and a customizable `sub` claim.
To enable V3 tokens for your organization:
1. Open the [OIDC Token Configuration](https://app.gitpod.io/settings/security/oidc) page in your organization settings
2. Select **V3** as the token version
3. Optionally configure extra sub claim fields
4. Save
Switching from V2 to V3 changes the `sub` claim format. Update your cloud provider trust policies before switching. See [V2 tokens](#v2-tokens) for the old format.
## Token structure
V3 tokens contain flat claims specific to the requesting principal. Every token includes the standard JWT claims (`iss`, `sub`, `aud`, `exp`, `iat`) plus principal-specific claims.
### Environment tokens
Issued when code running inside an environment requests a token.
```json theme={null}
{
"iss": "https://app.gitpod.io",
"sub": "organization_id:a1b2c3d4-...:project_id:c9d0e1f2-...",
"aud": ["sts.amazonaws.com"],
"exp": 1711929600,
"iat": 1711926000,
"environment_id": "e5f6a7b8-0000-4000-8000-000000000004",
"organization_id": "a1b2c3d4-0000-4000-8000-000000000001",
"project_id": "c9d0e1f2-0000-4000-8000-000000000005",
"runner_id": "f3a4b5c6-0000-4000-8000-000000000007",
"creator_principal": "user",
"creator_id": "b3c4d5e6-0000-4000-8000-000000000003",
"creator_email": "dev@example.com",
"creator_name": "Jane Doe",
"creator_idp": "https://accounts.google.com",
"creator_idp_claims": { "groups": ["engineering"] },
"environment_initializers": [
{
"git": {
"remote_uri": "https://github.com/org/repo.git"
},
"context_url": "https://github.com/org/repo"
}
]
}
```
### User tokens
Issued when a user requests a token directly (e.g., via the CLI outside an environment).
```json theme={null}
{
"iss": "https://app.gitpod.io",
"sub": "organization_id:a1b2c3d4-...:user_id:b3c4d5e6-...",
"aud": ["sts.amazonaws.com"],
"exp": 1711929600,
"iat": 1711926000,
"account_id": "d7e8f9a0-0000-4000-8000-000000000002",
"user_id": "b3c4d5e6-0000-4000-8000-000000000003",
"organization_id": "a1b2c3d4-0000-4000-8000-000000000001",
"email": "dev@example.com",
"name": "Jane Doe",
"idp": "https://accounts.google.com",
"idp_claims": { "groups": ["engineering"] }
}
```
### Service account tokens
Issued when a service account requests a token.
```json theme={null}
{
"iss": "https://app.gitpod.io",
"sub": "organization_id:a1b2c3d4-...:service_account_id:f0a1b2c3-...",
"aud": ["sts.amazonaws.com"],
"exp": 1711929600,
"iat": 1711926000,
"service_account_id": "f0a1b2c3-0000-4000-8000-000000000006",
"organization_id": "a1b2c3d4-0000-4000-8000-000000000001",
"name": "ci-bot"
}
```
### Account tokens
Issued for account-level operations (not scoped to an organization).
```json theme={null}
{
"iss": "https://app.gitpod.io",
"sub": "account_id:d7e8f9a0-...",
"aud": ["sts.amazonaws.com"],
"exp": 1711929600,
"iat": 1711926000,
"account_id": "d7e8f9a0-0000-4000-8000-000000000002",
"email": "admin@example.com",
"name": "Jane Admin",
"idp": "https://accounts.google.com",
"idp_claims": { "groups": ["engineering", "platform"] }
}
```
### Runner tokens
Issued for runner-level operations.
```json theme={null}
{
"iss": "https://app.gitpod.io",
"sub": "organization_id:a1b2c3d4-...:runner_id:f3a4b5c6-...",
"aud": ["sts.amazonaws.com"],
"exp": 1711929600,
"iat": 1711926000,
"runner_id": "f3a4b5c6-0000-4000-8000-000000000007",
"organization_id": "a1b2c3d4-0000-4000-8000-000000000001",
"runner_name": "us-east-prod"
}
```
## Subject claim (`sub`)
The V3 `sub` claim uses a `key:value` pair format separated by colons:
```
organization_id::project_id:
```
Each principal type has default sub claim keys:
| Principal | Default sub claim |
| ----------------------------- | --------------------------------------------------- |
| Environment (with project) | `organization_id::project_id:` |
| Environment (without project) | `organization_id:` |
| User | `organization_id::user_id:` |
| Service Account | `organization_id::service_account_id:` |
| Account | `account_id:` |
| Runner | `organization_id::runner_id:` |
### Customizing the sub claim
You can add extra fields to the `sub` claim to create more specific trust policies. Configure extra sub fields on the [OIDC Token Configuration](https://app.gitpod.io/settings/security/oidc) page.
Available extra sub fields:
| Field | Description | Principals |
| -------------------------------------------------- | ------------------------------------------ | ------------------------------------- |
| `creator_id` | ID of the user who created the environment | Environment |
| `creator_principal` | Principal type of the creator | Environment |
| `creator_email` | Email of the creator | Environment |
| `creator_name` | Name of the creator | Environment |
| `creator_idp` | Identity provider URL of the creator | Environment |
| `account_id` | Account ID | Account, User |
| `user_id` | User ID | User |
| `organization_id` | Organization ID | All (already in default sub for most) |
| `project_id` | Project ID | Environment |
| `runner_id` | Runner ID | Runner, Environment |
| `environment_id` | Environment ID | Environment |
| `email` | Email of the principal | User, Account |
| `name` | Name of the principal | User, Account, ServiceAccount |
| `idp` | Identity provider URL | User, Account |
| `runner_name` | Name of the runner | Runner |
| `service_account_id` | Service account ID | ServiceAccount |
| `environment_initializers.git.remote_uri` | Git remote URI | Environment |
| `environment_initializers.git.upstream_remote_uri` | Upstream git remote URI | Environment |
| `environment_initializers.context_url` | Context URL | Environment |
For example, adding `creator_email` produces a sub like:
```
organization_id::environment_id::creator_email:dev@example.com
```
This lets you write trust policies that restrict access to environments created by a specific developer.
## Setting up OIDC authentication
Setting up OIDC authentication involves three steps:
1. **Register Ona as an identity provider** with your cloud provider or third-party service. Use `https://app.gitpod.io` as the issuer URL.
2. **Configure trust rules** that define which token claims are required for access. Use the `sub` claim and other flat claims to implement fine-grained access control.
3. **Exchange the token** from within an Ona environment using the CLI. The cloud provider validates the token against Ona's JWKS endpoint and issues short-lived credentials.
## Provider-specific guides
* [AWS](/docs/ona/identity/aws-oidc)
* [Azure](/docs/ona/identity/azure-oidc)
* [GCP](/docs/ona/identity/gcp-oidc)
* [HashiCorp Vault](/docs/ona/identity/vault-oidc)
## CLI usage
Retrieve a token using `ona idp token`:
```bash theme={null}
ona idp token --audience sts.amazonaws.com
```
Decode the token to inspect claims:
```bash theme={null}
ona idp token --audience sts.amazonaws.com --decode
```
Use `ona idp login` for provider-specific authentication:
```bash theme={null}
# AWS
ona idp login aws --role-arn arn:aws:iam::123456789012:role/OnaRole
# HashiCorp Vault
ona idp login vault --role my-role
```
## OIDC discovery endpoint
Ona exposes a standard OIDC discovery endpoint at:
```
https://app.gitpod.io/.well-known/openid-configuration
```
The JSON Web Key Set (JWKS) for verifying token signatures is at:
```
https://app.gitpod.io/.well-known/jwks.json
```
The discovery endpoint returns the full list of supported claims, including all V3 claims:
```json theme={null}
{
"issuer": "https://app.gitpod.io",
"authorization_endpoint": "https://app.gitpod.io/auth/oauth2/authorize",
"token_endpoint": "https://app.gitpod.io/auth/oauth2/token",
"jwks_uri": "https://app.gitpod.io/.well-known/jwks.json",
"scopes_supported": ["openid"],
"response_types_supported": ["code", "id_token", "token"],
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": ["RS256"],
"claims_supported": [
"sub", "iss", "aud", "exp", "iat",
"org", "gsub",
"account_id", "user_id", "organization_id", "project_id",
"runner_id", "runner_manager_id", "environment_id", "service_account_id",
"environment_initializers",
"creator_principal", "creator_id", "creator_email", "creator_name",
"creator_idp", "creator_idp_claims",
"email", "name", "idp", "idp_claims",
"runner_name"
],
"code_challenge_methods_supported": ["S256"]
}
```
## V2 tokens
V2 is the previous token format. New integrations should use V3 tokens. V2 tokens remain fully supported and will continue to work. They do not receive new claims or features.
V2 tokens use a different `sub` claim format and include fewer claims. If your organization currently uses V2 tokens, existing integrations will continue to function without changes.
### V2 subject claim format
The V2 `sub` claim uses a path-based format:
* **Users:** `org:/user:`
* **Runners:** `org:/rnr:`
* **Environments without a project:** `org:/env:`
* **Environments from a project:** `org:/prj:/env:`
### V2 token example
```json theme={null}
{
"aud": "example.org",
"exp": 1740517845,
"iat": 1740514245,
"iss": "https://app.gitpod.io",
"org": "0191e223-1c3c-7607-badf-303c98b52d2f",
"sub": "org:0191e223-1c3c-7607-badf-303c98b52d2f/prj:019527e4-75d5-704d-a5a4-a2b52cf56198/env:019527e4-75d5-704d-a5a4-a2b52cf56196",
"gsub": { "principal": "environment", "id": "019527e4-75d5-704d-a5a4-a2b52cf56196" }
}
```
### V2 access control
You can match on the `sub` claim prefix to control access:
* **All environments in an org:** match `org:/*`
* **Environments from a project:** match `org:/prj:/*`
* **A specific environment:** match the full `sub` value
For V2-specific cloud provider setup, see the [V2 AWS guide](/docs/ona/integrations/aws).
**Read more:**
* [\[Auth0 docs\] OpenID Connect Protocol](https://auth0.com/authenticate/protocols/openid-connect-protocol)
# Custom domain
Source: https://ona.com/docs/ona/custom-domain
Set up a custom domain for your Ona management plane with TLS termination
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
This guide walks you through setting up a custom domain for your Ona management plane, enabling you to access Ona services through your own domain name with TLS termination.
## Overview
The setup involves two main steps:
1. **Register the custom domain** in your organization settings
2. **Configure cloud infrastructure** to route traffic to the Ona management plane
You can choose between **AWS** or **GCP** for your infrastructure:
* **AWS**: Uses VPC Endpoints and Network Load Balancer
* **GCP**: Uses Private Service Connect (PSC) and regional HTTPS Load Balancer
## Prerequisites
Before you begin, ensure you have:
* Admin access to your Ona organization settings
* **Single Sign-On (SSO) configured** - Custom domains require SSO to be set up. See the [SSO documentation](/docs/ona/sso/overview) for setup instructions.
* A registered domain name (e.g., `ona.example.com`)
* Browser access to `https://app.gitpod.io` to authenticate built-in integrations. If your network cannot allow this access, create a [custom organization MCP integration](/docs/ona/mcp#custom-organization-mcp-integrations) from your custom domain so its OAuth callback uses that domain.
- An AWS account with appropriate permissions
- An AWS Certificate Manager (ACM) certificate with Subject Alternative Names (SANs) covering **both**:
* Main domain: `ona.example.com`
* VSCode subdomain: `vscode.ona.example.com`
* A GCP project with billing enabled
* A VPC network and routable subnet (recommended /28 CIDR)
* A regional proxy-only subnet in your VPC (required for regional HTTPS load balancers)
* A regional SSL certificate (can be GCP-managed, but must be regional)
* Terraform installed locally
**About the VSCode subdomain:** The `vscode` subdomain (e.g., `vscode.ona.example.com`) serves a static VS Code Web application. This static content has no access to user data, source code, or any other resources unless the user is authenticated. Authentication is required before any user-specific data becomes accessible.
## Step 1: Register custom domain with Ona
Register your custom domain name with the management plane through the Ona dashboard.
1. Navigate to **Settings** → **Login & Identity** → **Login Configuration**
2. Click **Set Up** in the Custom Domain section
### Configure domain
Select your cloud provider (AWS or GCP) and enter the required information:
* **AWS Account ID**: The 12-digit AWS account ID where you will set up the infrastructure (Load Balancer, VPC Endpoint). Find this in the AWS Management Console under **My Account**.
* **Domain name**: Your custom domain (e.g., `ona.example.com`).
> Note: The AWS account ID you specify here must match the account where you create the VPC Endpoint. This is validated when requests come through your custom domain.
* **GCP Project ID**: The GCP project ID where you will deploy the infrastructure. Find this in the GCP Console under **Project Info**.
* **Domain name**: Your custom domain (e.g., `ona.example.com`).
> Note: The GCP project ID you specify here must match the project where you create the PSC endpoint. This is validated when requests come through your custom domain.
After registering your custom domain, you'll need to complete the cloud infrastructure setup below. **There is no automatic validation** - the configuration is verified only when requests are made through your custom domain.
## Step 2: Configure cloud infrastructure
Choose your cloud provider and follow the corresponding setup instructions.
Now that the domain is registered with Ona, you need to set up the AWS infrastructure to route traffic from your domain to the Ona management plane.
#### 2.1 Prepare your certificate
Ensure you have an AWS Certificate Manager (ACM) certificate that covers **both your custom domain and the VSCode subdomain**. This certificate will be used for TLS termination on the Load Balancer.
Your certificate must include both domains as Subject Alternative Names (SANs):
* `ona.example.com`
* `vscode.ona.example.com`
The certificate must be provisioned in the same AWS region where you'll create your Network Load Balancer.
If your certificate doesn't cover the VSCode subdomain, VS Code Browser integration will fail with certificate errors.
***
#### 2.2 Create security groups
Create two separate security groups: one for the Network Load Balancer and another for the VPC endpoint.
**Load Balancer security group**
Create a security group with the following rules:
* **Inbound**: HTTPS (443) from your desired source (e.g., your corporate network, internet).
* **Outbound**: HTTPS (443) to the VPC Endpoint security group (to be created below).
**VPC Endpoint security group**
Create a security group with the following rules:
* **Inbound**: HTTPS (443) from the Load Balancer security group (created above).
* **Outbound**: All traffic (or as per your security requirements).
Note the security group IDs for both; you'll need them for the following configuration.
***
#### 2.3 Create VPC endpoint
Create a VPC Endpoint to connect to the Ona management plane service.
**Configuration**
1. **Navigate to VPC Console** → **Endpoints** → **Create Endpoint**
2. **Service Configuration**:
* **Service category**: Select `Endpoint services that use NLBs and GWLBs`.
* **Service name**: `com.amazonaws.vpce.us-east-1.vpce-svc-00fa18d41fdd25cad`.
* Click **Verify service**.
*Create VPC Endpoint*
> ⚠️ Important: If you are in a region other than `us-east-1`, you must:
>
> * Enable **cross-region VPC endpoint**.
> * Specify `us-east-1` as the service region.
> * The VPC endpoint service is available in the following Availability Zone IDs:
>
> ```
> use1-az1
> use1-az2
> ```
>
> Note: AWS maps Availability Zone names (e.g., `us-east-1a`, `us-east-1b`) differently per account, so the name shown in your console may vary. Use the **AZ ID** (e.g., `use1-az1`) to identify the correct zone. You can find the AZ ID mapping for your account in the **EC2 > Subnets** console or by running `aws ec2 describe-availability-zones --region us-east-1`.
3. **VPC and Subnets**:
* Select the VPC and subnets where you want your VPC endpoint to be created.
* Select at least 2 Availability Zones for high availability.
*VPC Endpoint Network Settings*
4. **Security Groups**:
* Select the security group created earlier for the VPC endpoint.
5. **Create Endpoint** and wait for it to become **Available**.
6. **Note the Private IP Addresses**:
* Once the VPC Endpoint is available, navigate to the **Subnets** tab.
* Note down all the private IP addresses assigned to the endpoint (one per subnet/AZ).
*VPC Endpoint Private IPs*
***
#### 2.4 Create target group
Create a Target Group to route traffic from the Load Balancer to the VPC Endpoint.
**Configuration**
1. **Navigate to EC2 Console** → **Target Groups** → **Create Target Group**
2. **Basic Configuration**:
* **Target type**: IP addresses.
* **Target group name**: Give it a descriptive name (e.g., `ona-vpce-targets`).
* **Protocol**: TCP.
* **Port**: 443.
* **VPC**: Select the same VPC.
*Target Group Configuration*
3. **Health Checks**:
* **Protocol**: TCP.
* Leave the default health check settings.
4. **Register Targets**:
* Click **Next**.
* Add each private IP address from the VPC Endpoint (noted in step 2.3).
* **Port**: 443 for each IP.
* Click **Include as pending below**.
* Click **Create target group**.
*Register Target IPs*
***
#### 2.5 Create Network Load Balancer
Create a Network Load Balancer (NLB) to handle incoming traffic.
**Configuration**
1. **Navigate to EC2 Console** → **Load Balancers** → **Create Load Balancer**
2. **Choose Load Balancer Type**:
* Select **Network Load Balancer**.
*Choose Load Balancer Type*
3. **Configure Load Balancer**:
* **Name**: Give it a descriptive name (e.g., `ona-custom-domain-lb`).
* **Scheme**: Choose **Internal** or **Internet-facing** based on your access requirements.
* **IP address type**: IPv4.
* **VPC**: Select the VPC of your VPC endpoint.
* **Availability Zones**: Select the same Availability Zones chosen for the VPC endpoint (must be at least 2).
4. **Select the Security Group**:
*Load Balancer Security Groups*
* Select the security group created earlier for the load balancer.
5. **Configure Listener**:
* **Protocol**: TLS.
* **Port**: 443.
* **Default action**: Forward to the target group created in step 2.4.
* **Default SSL/TLS server certificate**: Select the ACM certificate you prepared.
* ⚠️ **ALPN policy**: Select **HTTP/2 preferred** as the ALPN policy. This is important for optimal performance when connecting to the management plane.
*Listener Configuration*
6. **Create Load Balancer**.
#### 2.6 Route runner API traffic privately
If you create AWS runners from your custom domain, the runner connects back to the management plane URL it receives during setup, for example `https://ona.example.com/api`. The custom-domain path already goes through your Network Load Balancer. To keep runner API traffic private, use split-horizon DNS so the runner VPC resolves your custom domain to the private load-balancer endpoint instead of the public DNS record or external proxy path.
Do not point `ona.example.com` directly at the custom-domain VPC endpoint. The AWS custom-domain endpoint expects traffic from your Network Load Balancer after TLS termination and Proxy Protocol v2 handling. A runner connects with HTTPS, so bypassing the load balancer would skip the certificate you manage in ACM and the request would not be handled correctly.
Use one of these DNS patterns:
* **Runner in the same VPC**: create a private DNS record for `ona.example.com` that aliases to the internal Network Load Balancer DNS name.
* **Runner in a different VPC**: associate the private hosted zone with the runner VPC, or configure Route 53 Resolver forwarding so the runner VPC resolves `ona.example.com` to the internal Network Load Balancer DNS name.
This keeps the same load-balancer and VPC endpoint architecture as user traffic, but makes runners reach it through private DNS and private routing. Ensure the runner subnets can route to the internal Network Load Balancer and that the load balancer security group allows HTTPS (443) from the runner security group or runner subnet CIDR.
Now that the domain is registered with Ona, you need to set up the GCP infrastructure to route traffic from your domain to the Ona management plane using Private Service Connect (PSC).
The GCP setup uses a Terraform module that creates:
* A Private Service Connect (PSC) endpoint to connect to the Ona service
* A regional HTTPS Load Balancer with TLS termination
* A 300 second backend service timeout for long-running agent and editor streams
* Automatic project ID header injection for authentication
#### 2.1 Prepare your certificate
Create a regional SSL certificate in GCP Certificate Manager. The certificate must be regional (not global) to work with the regional HTTPS load balancer.
Your certificate must cover **both your custom domain and the VSCode subdomain**:
* `ona.example.com`
* `vscode.ona.example.com`
```bash theme={null}
# Example: Create a GCP-managed regional certificate with both domains
gcloud certificate-manager certificates create ona-custom-domain-cert \
--domains="ona.example.com,vscode.ona.example.com" \
--location=us-central1
```
If your certificate doesn't cover the VSCode subdomain, VS Code Browser integration will fail with certificate errors.
Note the full certificate resource ID, which follows this format:
```
projects/YOUR_PROJECT_ID/locations/REGION/certificates/CERT_NAME
```
***
#### 2.2 Prepare network prerequisites
Ensure your VPC has the following:
1. **A routable subnet** with available IP addresses (recommended /28 CIDR minimum)
2. **A regional proxy-only subnet** - required for regional HTTPS load balancers
To create a proxy-only subnet if you don't have one:
```bash theme={null}
gcloud compute networks subnets create proxy-only-subnet \
--purpose=REGIONAL_MANAGED_PROXY \
--role=ACTIVE \
--region=us-central1 \
--network=YOUR_VPC_NAME \
--range=10.129.0.0/23
```
***
#### 2.3 Deploy with Terraform
Use the Ona GCP Terraform module to deploy the infrastructure.
The custom domain sub-module is available at: [gitpod-io/terraform-google-ona-runner](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/modules/custom-domain-client-infra)
Use a module version that sets the regional backend service timeout to `300` seconds. If you manage equivalent load balancer resources outside the module, set the backend service timeout to at least `300` seconds so long-running agent and editor streams are not closed by the load balancer.
**Configure authentication**
```bash theme={null}
gcloud auth application-default login
```
**Create a Terraform configuration**
Create a new directory for the custom domain configuration:
```bash theme={null}
mkdir ona-custom-domain && cd ona-custom-domain
```
Create a `main.tf` that references the custom domain sub-module and wires variables through:
```hcl theme={null}
# main.tf
module "custom_domain" {
source = "gitpod-io/ona-runner/google//modules/custom-domain-client-infra"
version = "~> 1.0"
project_id = var.project_id
region = var.region
vpc_network = var.vpc_network
subnet_name = var.subnet_name
domain_name = var.domain_name
certificate_manager_cert_id = var.certificate_manager_cert_id
load_balancer_type = var.load_balancer_type
}
```
Create a `variables.tf`:
```hcl theme={null}
# variables.tf
variable "project_id" {
type = string
}
variable "region" {
type = string
}
variable "vpc_network" {
type = string
}
variable "subnet_name" {
type = string
}
variable "domain_name" {
type = string
}
variable "certificate_manager_cert_id" {
type = string
}
variable "load_balancer_type" {
type = string
}
```
Create a `terraform.tfvars` and fill in your values:
```hcl theme={null}
# terraform.tfvars
project_id = "your-gcp-project-id"
region = "us-central1"
# Network Configuration
vpc_network = "default"
subnet_name = "default"
# Domain and SSL Configuration
domain_name = "ona.example.com"
certificate_manager_cert_id = "projects/your-gcp-project-id/locations/us-central1/certificates/ona-custom-domain-cert"
# Load Balancer Type: "internal" (private) or "external" (public)
load_balancer_type = "internal"
```
**Deploy the infrastructure**
```bash theme={null}
terraform init
terraform plan
terraform apply
```
**Verify the deployment**
```bash theme={null}
# Get the load balancer IP
terraform output load_balancer_ip
# Check PSC connection status
gcloud compute forwarding-rules describe gitpod-custom-domain-psc \
--region=us-central1 \
--format="get(pscConnectionStatus)"
```
The PSC connection status should show `ACCEPTED` once the connection is established.
***
## Step 3: Configure DNS
Point your custom domain to the Load Balancer.
You need to create **two DNS records**: one for the main custom domain and one for the VSCode subdomain.
1. **Get Load Balancer DNS Name**:
* In the Load Balancer details, copy the **DNS name**.
*Load Balancer DNS Name*
2. **Create DNS Records**:
* In your DNS provider (Route 53, Cloudflare, etc.), create the following records:
**Main custom domain record:**
* **Name**: Your custom domain (e.g., `ona.example.com`).
* **Type**: CNAME (or ALIAS if using Route 53).
* **Value**: Load Balancer DNS name.
**VSCode subdomain record:**
* **Name**: `vscode.` prefix with your custom domain (e.g., `vscode.ona.example.com`).
* **Type**: CNAME (or ALIAS if using Route 53).
* **Value**: Load Balancer DNS name (same as above).
> Note: Both DNS records must point to the same Load Balancer. The VSCode subdomain is required for VS Code Browser integration to work properly with your custom domain.
If the Network Load Balancer is internal, create both records, including `vscode.ona.example.com`, in private DNS that is reachable from your users' networks and runner VPCs. Both records must resolve through the internal Network Load Balancer DNS name to its private IP addresses. Do not publish records that point users to an internal load balancer unless those users resolve DNS and route traffic from connected private networks.
Create **two DNS records**: one for the main custom domain and one for the VSCode subdomain. Both records must point to the Load Balancer IP address.
1. **Get Load Balancer IP**:
```bash theme={null}
terraform output load_balancer_ip
```
2. **Create DNS Records**:
* In your DNS provider, create the following A records:
**Main custom domain record:**
* **Name**: Your custom domain (e.g., `ona.example.com`).
* **Type**: A.
* **Value**: Load Balancer IP address.
**VSCode subdomain record:**
* **Name**: `vscode.` prefix with your custom domain (e.g., `vscode.ona.example.com`).
* **Type**: A.
* **Value**: Load Balancer IP address (same as above).
**Example using Cloud DNS:**
```bash theme={null}
gcloud dns record-sets create ona.example.com. \
--zone=your-dns-zone \
--type=A \
--ttl=300 \
--rrdatas="LOAD_BALANCER_IP"
gcloud dns record-sets create vscode.ona.example.com. \
--zone=your-dns-zone \
--type=A \
--ttl=300 \
--rrdatas="LOAD_BALANCER_IP"
```
> Note: Both DNS records must point to the same Load Balancer IP address. The VSCode subdomain is required for VS Code Browser integration to work with your custom domain.
If using an internal Load Balancer (`load_balancer_type = "internal"`), create both records in private DNS and point them to the Load Balancer's private IP address. Ensure your DNS is accessible from within your VPC or configure appropriate DNS forwarding. For external load balancers, use your public DNS provider.
***
## Step 4: Verify setup
1. Wait for DNS propagation (typically 5-15 minutes).
2. Access your custom domain in a browser: `https://ona.example.com`.
3. Verify that:
* TLS certificate is valid.
* You can reach the Ona management plane.
* No certificate warnings appear.
***
## Step 5: Update your SSO configuration
Update your SSO configuration to allow the new redirect URL using your custom domain:
```
https://ona.example.com/auth/oidc/callback
```
This step is **required** - authentication will fail without updating the SSO callback URL. See the [SSO documentation](/docs/ona/sso/overview) for provider-specific instructions.
***
## Step 6: Recreate your runner
Recreate each runner from your custom domain. This is the recommended path because the runner API endpoint is written into the runner infrastructure during setup.
1. Open Ona from your custom domain, for example `https://ona.example.com`.
2. Create a new runner from **Settings** -> **Runners**.
3. Deploy the runner by following the setup guide for [AWS](/docs/ona/runners/aws/setup) or [GCP](/docs/ona/runners/gcp/setup).
4. Create new environments on the new runner.
5. After environments on the old runner are stopped or no longer needed, delete the old runner.
Existing environments can only be accessed from the endpoint that created them. If an environment was created from `https://app.gitpod.io`, open it from `https://app.gitpod.io`. If it was created from your custom domain, open it from your custom domain. Mixing endpoints can cause editor, browser, and port connection issues.
If Ona detects that you opened an environment from another domain, a warning at the top of the environment links to the domain that created it.
### Migrate your runner instead
Migrate an existing runner only when you cannot recreate it. Migration changes the runner's management-plane API endpoint, but it does not move existing environments between endpoints. Existing environments must still be opened from the endpoint they were created from, which is why recreating the runner is recommended.
Keep the runner ID unchanged when you migrate a runner. Update both the runner API endpoint and the runner token. The runner token includes the issuer for the endpoint that created it. If you update only the API endpoint, the runner can fail OIDC discovery with an issuer mismatch.
Use the endpoint you are moving the runner to when creating the new runner token:
* To move from `https://app.gitpod.io` to your custom domain, use `https://ona.example.com/api`.
* To move back to the default domain, use `https://app.gitpod.io/api`.
Create a new runner exchange token. Use a [personal access token](/docs/ona/integrations/personal-access-token) for an organization admin or another token with permission to administer runners.
Create the personal access token from the same management-plane domain you are moving the runner to. When moving to your custom domain, do not use a personal access token created from `https://app.gitpod.io`. For example, open `https://ona.example.com/settings/personal-access-tokens` and use that token as `ONA_TOKEN` in the command below.
```bash theme={null}
export API_ENDPOINT="https://ona.example.com/api"
export RUNNER_ID=""
read -rsp "Ona API token: " ONA_TOKEN; echo
EXCHANGE_TOKEN="$(
curl -fsS \
-H "Authorization: Bearer ${ONA_TOKEN}" \
-H "Content-Type: application/json" \
-H "Connect-Protocol-Version: 1" \
--data "{\"runnerId\":\"${RUNNER_ID}\"}" \
"${API_ENDPOINT}/gitpod.v1.RunnerService/CreateRunnerToken" \
| jq -er '.exchangeToken'
)"
```
The exchange token is one-time use and expires after 24 hours. Creating a new exchange token does not expire previously issued runner tokens.
Update the CloudFormation stack that manages the runner:
1. Open the runner's CloudFormation stack in the AWS Console.
2. Click **Update**.
3. Select **Use existing template** unless you are also upgrading the runner template.
4. In **Ona Configuration**, set **Ona API Endpoint** to the target endpoint, for example `https://ona.example.com/api`.
5. Set **Runner Token** to the `EXCHANGE_TOKEN` value from the command above.
6. Keep **Runner ID** unchanged.
7. Review the change set and complete the stack update.
8. Wait for the ECS services to stabilize, then verify the runner status from the target endpoint.
If you automate the CloudFormation update, pass the current value for every unchanged parameter and update only `APIEndpoint` and `ExchangeToken`.
Update the Terraform configuration and rotate the runner token secret:
1. In the runner Terraform directory, update `api_endpoint`:
```hcl theme={null}
api_endpoint = "https://ona.example.com/api"
```
2. Add a new Secret Manager version for the runner token. The GCP runner module creates the token secret as `-runner-token`, where `runner_name` is the Terraform variable you used for the runner. If you cannot use the `gcloud` CLI, add a new version to the same secret in the Google Cloud Console and use this JSON as the secret value:
```json theme={null}
{
"join_token": "",
"created_by": "manual-migration"
}
```
Replace `` with the `EXCHANGE_TOKEN` value from the command above.
```bash theme={null}
export GCP_PROJECT=""
export RUNNER_NAME=""
export SECRET_NAME="${RUNNER_NAME}-runner-token"
jq -nc --arg token "$EXCHANGE_TOKEN" \
'{join_token:$token, created_by:"manual-migration"}' \
| gcloud secrets versions add "$SECRET_NAME" \
--project="$GCP_PROJECT" \
--data-file=-
```
3. Re-initialize Terraform and apply the endpoint change:
```bash theme={null}
terraform init -upgrade
terraform plan -out=tfplan
terraform apply tfplan
```
4. Review the plan before applying. The endpoint change should roll the runner and proxy instance templates or managed instance groups.
5. Verify the runner status from the target endpoint.
Updating `runner_token` in `terraform.tfvars` alone is not enough for existing GCP runners, because the module ignores changes to the initial Secret Manager secret version after creation.
***
## Step 7: Enforce custom domain access (Optional)
After completing the setup, you can optionally enable a policy to require all users to access Ona exclusively through your custom domain:
1. Navigate to **Settings** → **Login & Identity** → **Login Configuration**.
2. Enable **Enforce custom domain access**.
When enabled:
* All users, including organization admins, will be blocked from accessing via the default domain (`app.gitpod.io`).
* This ensures all traffic goes through your controlled infrastructure.
Users who are currently logged in with an active session can continue using the default domain until their session expires. The enforcement only applies to new login attempts.
Before enabling this policy, verify that your custom domain setup is fully functional.
***
## Troubleshooting
If you cannot connect to your custom domain:
1. Verify DNS propagation using `dig` or `nslookup`.
2. Check that the Load Balancer is in an **Active** state.
3. Verify the target group or backend service shows healthy targets.
4. Ensure security group rules (AWS) or firewall rules (GCP) allow traffic from your source.
If you see certificate warnings:
1. Verify the ACM certificate covers **both** your main domain and the VSCode subdomain (`ona.example.com` and `vscode.ona.example.com`).
2. Check that the certificate is attached to the Load Balancer listener.
3. Ensure the certificate is valid and not expired.
4. If using VS Code Browser, verify the certificate includes both the main domain and the VSCode subdomain in its Subject Alternative Names (SANs).
1. Verify the Certificate Manager certificate covers your custom domain.
2. Ensure the certificate is regional (not global) and in the same region as your load balancer.
3. Check that the certificate is attached to the HTTPS proxy.
4. Verify the certificate status is `ACTIVE`:
```bash theme={null}
gcloud certificate-manager certificates describe YOUR_CERT_NAME \
--location=REGION
```
If you experience slow connections:
1. Verify the ALPN policy is set to **HTTP/2 preferred** on the Load Balancer listener.
2. Check that you've selected at least 2 Availability Zones for high availability.
3. Verify the VPC Endpoint is in an **Available** state.
1. Check the backend service health status:
```bash theme={null}
gcloud compute backend-services get-health ona-custom-domain-backend \
--region=REGION
```
2. Verify the PSC endpoint is in an **ACCEPTED** state.
3. Verify the regional backend service timeout is at least `300` seconds:
```bash theme={null}
gcloud compute backend-services describe ona-custom-domain-backend \
--region=REGION \
--format="value(timeoutSec)"
```
4. If the timeout is lower than `300`, update it:
```bash theme={null}
gcloud compute backend-services update ona-custom-domain-backend \
--region=REGION \
--timeout=300
```
5. Check load balancer logs for any errors.
**AWS Account ID mismatch**
If you see "AWS account ID mismatch" errors:
1. Verify the VPC Endpoint was created in the same AWS account registered in your custom domain settings.
2. Check the AWS account ID in **Settings** → **Login & Identity** → **Login Configuration** → **Domain & Access**.
3. If the account ID is incorrect, edit the custom domain configuration to update it.
**VPC Endpoint connection issues**
If you see "Failed to resolve VPC Endpoint ID" errors:
1. Verify the VPC Endpoint is connected to the Ona VPC Endpoint Service.
2. Check that **Proxy Protocol v2** is enabled on the Network Load Balancer target group.
3. Ensure the VPC Endpoint is in an **Available** state.
4. Verify the target group shows healthy targets.
**PSC connection not accepted**
If the PSC connection status is not `ACCEPTED`:
1. Check that your GCP project ID matches what was registered in the custom domain settings.
2. Contact [Ona support](https://ona.com/support) or reach out to your account executive to verify the service attachment is configured to accept connections from your project.
**GCP Project ID mismatch**
If you see "GCP project ID mismatch" errors:
1. Verify the infrastructure was deployed in the same GCP project registered in your custom domain settings.
2. Check the GCP project ID in **Settings** → **Login & Identity** → **Login Configuration** → **Domain & Access**.
3. The `X-Gitpod-GCP-ID` header is automatically injected by the load balancer - ensure the Terraform configuration uses the correct `project_id` variable.
**Proxy-only subnet issues**
If the load balancer fails to create:
1. Verify you have a regional proxy-only subnet in your VPC:
```bash theme={null}
gcloud compute networks subnets list \
--filter="purpose=REGIONAL_MANAGED_PROXY" \
--regions=REGION
```
2. If missing, create one as described in the prerequisites.
For additional support, Enterprise customers can reach out to your account manager.
# Veto - Datawall
Source: https://ona.com/docs/ona/guardrails/datawall
Detect confidential data leaving Ona environments over the network using kernel-level fingerprinting.
Datawall is not yet available. It will require an [Enterprise plan](https://ona.com/pricing). This page describes planned functionality.
Datawall is a Veto control for detecting confidential data leaving an Ona environment over the network. It runs below the agent, at the kernel level, so the process attempting the transfer cannot disable or inspect the mechanism that is evaluating it.
## When to use Datawall
Use Datawall when you want stronger protections around code, credentials, tickets, prompts, or other sensitive material that enters an environment and should not leave it unchecked.
Typical use cases:
* environments handling confidential repositories or internal documentation
* agents reading tickets, MCP responses, or secrets that should not be copied out
* teams that need an explicit exfiltration control in addition to identity, policy, and audit logs
## How Datawall works
When confidential data enters the environment, Ona registers that material for monitoring. The kernel fingerprints it and compares outbound network traffic against those fingerprints.
This is designed to catch transfers across common network paths, including:
* HTTP and HTTPS
* SSH-based traffic such as `git push` and `scp`
* traffic relayed through helper processes
* common encoding transforms such as base64, hex, and URL encoding
## What Datawall detects well
| Scenario | Detected |
| ----------------------------------------------------------- | -------- |
| Agent sends data verbatim over HTTP or HTTPS | Yes |
| Agent encodes data before sending | Yes |
| Agent relays data through a child process | Yes |
| Agent writes data to disk and another process sends it | Yes |
| Agent sends data over SSH | Yes |
| Agent encrypts data at the application layer before sending | Yes |
| Agent splits data across multiple requests | Partial |
| Agent paraphrases or rewrites the data | No |
## Operating and investigating
Every detection produces a structured event that is written to environment logs and reported to the management plane. Review the event to understand:
* which action triggered the match
* where the traffic was going
* which process attempted the transfer
* when the detection occurred
## Related pages
* [Veto overview](/docs/ona/guardrails/veto)
* [Executable deny list](/docs/ona/organizations/policies/executable-deny-list)
* [Guardrails overview](/docs/ona/guardrails/overview)
# Guardrails
Source: https://ona.com/docs/ona/guardrails/overview
Understand the identity, policy, enforcement, and audit controls that govern Ona environments and agents.
Guardrails are the controls that let teams adopt Ona without giving up administrative or security oversight. They span identity, organization policy, kernel-level enforcement, and auditability.
Use this section when you are answering questions like:
* who can access Ona and how they sign in
* what environments and agents are allowed to do
* which defaults apply across the organization
* how to investigate or explain agent behavior later
## What guardrails cover
Ona uses several layers of control:
| Layer | What it controls | Start here |
| ------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| Identity | Who can sign in and what access model you use | [SSO](/docs/ona/sso/overview), [SCIM](/docs/ona/scim/overview), [OIDC](/docs/ona/configuration/oidc) |
| Policy | Which defaults, limits, and restrictions apply across the organization | [Organization policies](/docs/ona/organizations/policies/overview) |
| Runtime enforcement | What can execute and what data can leave an environment | [Veto](/docs/ona/guardrails/veto), [Command deny list](/docs/ona/command-deny-list) |
| Auditability | What happened, when, and under which identity | [Audit logs](/docs/ona/audit-logs/overview) |
## How to roll guardrails out
Most teams do not turn on every control at once. A practical rollout usually looks like this:
1. Connect [identity](/docs/ona/sso/overview) so access is tied to your existing org model.
2. Apply a small set of [organization policies](/docs/ona/organizations/policies/overview) for environment limits, lifecycle, and standardization.
3. Add runtime controls where you have clear risk boundaries:
* [command deny list](/docs/ona/command-deny-list) for broad command restrictions
* [Veto executable deny list](/docs/ona/organizations/policies/executable-deny-list) for kernel-level executable blocking
* [Datawall](/docs/ona/guardrails/datawall) for confidential data leaving the environment (coming soon)
4. Review [audit logs](/docs/ona/audit-logs/overview) as part of rollout so admins know how to inspect outcomes and policy changes.
## Which controls to choose first
Start with the control that matches the risk you are trying to reduce:
* **Access and provisioning risk**: start with [SSO](/docs/ona/sso/overview), [SCIM](/docs/ona/scim/overview), and [organization roles](/docs/ona/organizations/organization-roles)
* **Resource sprawl or inconsistent setups**: start with [organization policies](/docs/ona/organizations/policies/overview)
* **Risky commands or binaries**: start with [command deny list](/docs/ona/command-deny-list) or [Veto executable deny list](/docs/ona/organizations/policies/executable-deny-list)
* **Source code or credential exfiltration concerns**: review [Veto](/docs/ona/guardrails/veto) and [Datawall](/docs/ona/guardrails/datawall) (coming soon)
* **Compliance and post-incident review**: start with [audit logs](/docs/ona/audit-logs/overview)
## Related pages
* [Veto overview](/docs/ona/guardrails/veto)
* [Organization policies](/docs/ona/organizations/policies/overview)
* [Identity](/docs/ona/sso/overview)
* [Audit logs](/docs/ona/audit-logs/overview)
# Veto
Source: https://ona.com/docs/ona/guardrails/veto
Kernel-level enforcement engine that protects AI agent environments from unauthorized execution and data exfiltration.
Veto is Ona's kernel-level enforcement engine for AI agents. It runs as a Linux Security Module (LSM) inside the environment kernel, below the agent, below userspace. The LLM cannot bypass or disable it.
AI agents reason about security boundaries and work around them. Traditional runtime security operates above the agent, making it observable and evadable. Veto moves enforcement below the agent's reach.
## Capabilities
## Kernel-level enforcement
When enforcement operates above the agent, the agent can discover and circumvent it. Path-based deny lists fall to renamed binaries. Userspace sandboxes can be disabled. Proxy-based DLP is avoided by encoding data differently.
Veto enforces at the syscall level. The agent cannot unload the LSM, modify its configuration, or observe whether an action was flagged. The kernel is the last trust boundary before hardware.
## Watch: Claude Code vs. Veto
Leonardo walks through how Claude Code bypasses traditional guardrails and how Veto enforces controls from inside the kernel.
## Further reading
* [How Claude Code Escapes Its Own Denylist and Sandbox](https://ona.com/stories/how-claude-code-escapes-its-own-denylist-and-sandbox) - Leonardo's research post that motivated Veto
* [The enterprise agent problem Claude Code wasn't built to solve](https://ona.com/stories/enterprise-agent-problem) - Matt Boyle on the platform layer enterprises need around coding agents
* [Introducing Veto](https://ona.com/stories/introducing-veto-security-for-the-next-era-of-software) - announcement and technical overview
# AWS (V2)
Source: https://ona.com/docs/ona/integrations/aws
Access AWS resources from environments using OIDC V2 tokens.
This guide covers **V2 OIDC tokens**. For new integrations, see the [AWS OIDC V3 guide](/docs/ona/identity/aws-oidc), which uses the current token format with flat claims and customizable sub fields. V2 tokens remain fully supported.
Ona environments can retrieve AWS credentials using [OpenID Connect (OIDC)](/docs/ona/configuration/oidc) - no static credentials needed.
The `ona` CLI generates a JWT token with claims about the environment and owner, which AWS exchanges for an STS token associated with an IAM role you configure.
## Step 1: Create an AWS identity provider
Create an [OIDC identity provider](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html) in AWS to establish trust with Ona:
* **Provider URL**: `https://app.gitpod.io`
* **Audience**: `sts.amazonaws.com`
View the OIDC configuration at `https://app.gitpod.io/.well-known/openid-configuration`
See [Identity providers and federation](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers.html) in AWS docs.
## Step 2: Create an IAM role with a trust policy
[Create an IAM role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp.html) that Ona environments can assume. Use JWT claims to restrict which environments can assume the role.
Follow the principle of least privilege - only allow relevant environments and users to assume your role.
```json theme={null}
{
"Claims": {
"aud": "sts.amazonaws.com",
"exp": 1740517845,
"iat": 1740514245,
"iss": "https://app.gitpod.io",
"org": "0191e223-1c3c-7607-badf-303c98b52d2f",
"sub": "org:0191e223-1c3c-7607-badf-303c98b52d2f/prj:019527e4-75d5-704d-a5a4-a2b52cf56198/env:019527e4-75d5-704d-a5a4-a2b52cf56196"
},
"Header": [
{
"KeyID": "k0",
"JSONWebKey": null,
"Algorithm": "RS256",
"Nonce": "",
"ExtraHeaders": null
}
]
}
```
Inspect claims by running `ona idp token --decode --audience sts.amazonaws.com` in an environment. Note the `sub` claim contains organization, project, and environment IDs.
Define condition keys using the OIDC provider name (`app.gitpod.io`) plus the claim (`:aud`, `:sub`, etc.):
**Allow all environments in an organization:**
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::981341800645:oidc-provider/app.gitpod.io"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"app.gitpod.io:aud": "sts.amazonaws.com"
},
"StringLike": {
"app.gitpod.io:sub": "org:0191e223-1c3c-7607-badf-303c98b52d2f/*"
}
}
}
]
}
```
**Allow only environments from a specific project:**
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::981241700645:oidc-provider/app.gitpod.io"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"app.gitpod.io:aud": "sts.amazonaws.com"
},
"StringLike": {
"app.gitpod.io:sub": "org:0191e223-1c3c-7607-badf-303c98b52d2f/prj:019527e4-75d5-704d-a5a4-a2b52cf56198/*"
}
}
}
]
}
```
See [OIDC condition keys](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html#condition-keys-wif) and [string condition operators](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html#Conditions_String) in AWS docs.
## Step 3: Assume the role
Requires AWS CLI installed in your environment.
Use `ona idp login aws` to assume the role and update your AWS credentials file:
* `--duration-seconds` sets token expiry (default: 3600 seconds, longer sessions require AWS admin approval)
You can run this manually or add it to your [automations](/docs/ona/configuration/tasks-and-services/overview) for automatic authentication on startup:
```bash theme={null}
ona idp login aws --role-arn [--duration-seconds=]
aws secretsmanager get-secret-value --secret-id database_connection_string --region us-east-1 | jq .SecretString
```
See [`assume-role-with-web-identity`](https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role-with-web-identity.html) in AWS docs.
## FAQ
Any resource accessible via AWS CLI or SDK works in Ona, provided your IAM role has the required permissions. The [STS token](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html) you receive can access EC2, EKS, S3, RDS, and more.
Access depends entirely on the policies attached to your assumed IAM role. Configure permissions in AWS IAM as you would for any other OIDC-based access.
## Troubleshooting
Use `ona idp token --decode --audience sts.amazonaws.com` to print your environment JWT token. Ensure that any claims against the `sub` match the trust policy in AWS.
# Personal access tokens
Source: https://ona.com/docs/ona/integrations/personal-access-token
Authenticate CLI and SDK access for automation and CI/CD.
Personal access tokens (PATs) authenticate programmatic access to Ona via the [CLI](/docs/ona/integrations/cli) or [SDK](/docs/ona/integrations/sdk).
## Create a token
1. Go to [Personal access tokens](https://app.ona.com/settings/personal-access-tokens)
2. Click "New Token"
3. Enter a description and select expiration (30, 60, or 90 days)
4. Choose an access level:
* **Read-only** - the token can only read data. All write operations are denied.
* **Read & Write** - the token can both read and modify data.
5. Click "Create" and copy the token immediately - you won't see it again
## Use a token
```bash theme={null}
ona login --token
```
Or set the environment variable:
```bash theme={null}
export ONA_TOKEN=
ona login
```
## Permissions
Tokens inherit your user account's permissions and can be scoped to one of two access levels:
| Access level | Description |
| ---------------- | ---------------------------------------------------------------------------- |
| **Read-only** | Can list and retrieve resources but cannot create, update, or delete them. |
| **Read & Write** | Full access. Can perform any action your user account is allowed to perform. |
The access level is set at creation time and cannot be changed afterward. To switch access levels, revoke the existing token and create a new one.
## Security
* Treat tokens like passwords - don't share or store insecurely
* Use the shortest expiration that meets your needs
* Revoke unused tokens
* Actions are logged in audit logs with the token ID
## Examples
### CI/CD integration
Authenticate your CI/CD pipeline to create and manage environments.
```yaml theme={null}
name: Ona Integration
on: [push]
jobs:
create-environment:
runs-on: ubuntu-latest
steps:
- name: Create Environment
env:
ONA_TOKEN: ${{ secrets.ONA_PAT }}
ONA_CLASS: some-class-id
run: |
ona login --token $ONA_TOKEN
ona environment create --class-id $ONA_CLASS https://github.com/your-repo
```
### Scripted environment management
Manage environments programmatically for bulk operations.
```python theme={null}
import subprocess
import json
ONA_PAT = "your_personal_access_token"
def run_ona_command(*args):
result = subprocess.run(
["ona"] + list(args),
capture_output=True,
text=True,
check=True
)
return result.stdout.strip()
# Login using PAT
run_ona_command("login", "--token", ONA_PAT)
# List all environments
environments_json = run_ona_command("environment", "list", "-o", "json")
environments = json.loads(environments_json)
# Stop all running environments
for env in environments:
if env['status']['phase'] == 'ENVIRONMENT_PHASE_RUNNING':
print(f"Stopping environment {env['id']}")
run_ona_command("environment", "stop", env['id'])
print("All running environments have been stopped.")
```
### Third-party tool integration
Create environments from external tools.
```python theme={null}
import subprocess
import json
ONA_PAT = "your_personal_access_token"
def create_environment_for_review(repo_url):
# Login using PAT
subprocess.run(["ona", "login", "--token", ONA_PAT], check=True)
# Create an environment
result = subprocess.run(
["ona", "environment", "create", repo_url, "--dont-wait"],
capture_output=True,
text=True,
check=True
)
env_id = result.stdout.strip()
# Get the environment details
result = subprocess.run(
["ona", "environment", "get", env_id, "-o", "json"],
capture_output=True,
text=True,
check=True
)
return json.loads(result.stdout)
```
# Manage groups
Source: https://ona.com/docs/ona/organizations/groups
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Groups let you manage access to projects and runners at scale. You can share resources with individual users for direct access, or assign members to groups and share resources with those groups for easier management of larger teams. Groups control access; they don't track usage. To attribute credit consumption or set per-team budgets, use [teams](/docs/ona/organizations/teams) instead. See [Groups vs. teams](/docs/ona/organizations/overview#groups-vs-teams) for a side-by-side comparison.
## How access works
When you create a project, you automatically become its admin. Only you and organization admins can access it initially. To share with your team, either:
* Share with specific users or groups (recommended for controlled access)
* Grant access to everyone in the organization
For team members to use a project, they need access to **both** the project and at least one runner the project uses.
The Share dialog warns you when this might be an issue.
## Managing groups
### Create a group
1. Go to **Settings → Members → Groups**
2. Click **New Group**
3. Enter a name and optional description
4. Optionally add members during creation
5. Click **Create**
### Add members
1. Click on the group
2. Click **Add People**
3. Select members and click **Add**
### Remove members
1. Open the group
2. Select members using checkboxes
3. Click **Remove**
Members immediately lose access to resources shared exclusively with that group.
### Delete a group
1. Open the group
2. Click **⋯** → **Delete**
3. Confirm
Deletion is permanent. Members lose access to resources shared only with this group.
## Organization roles
Groups can be assigned organization-wide roles, giving all members role-specific access to resources across the entire organization.
| Role | Access granted |
| --------------------- | ------------------------------------------------- |
| **Runners Admin** | All runners |
| **Projects Admin** | All projects |
| **Groups Admin** | All groups |
| **Automations Admin** | All automations |
| **Insights Viewer** | Read-only access to Insights |
| **Audit Log Reader** | Read-only access to audit logs |
| **Billing Viewer** | Read-only access to billing and usage information |
To assign organization roles to a group, see [Assign an organization role](/docs/ona/organizations/organization-roles#assign-an-organization-role).
For detailed permissions and use cases, see [Organization roles](/docs/ona/organizations/organization-roles).
## Roles and Permissions
The roles below apply to individual resources (projects, runners, automations) and are distinct from the organization-wide roles described above.
When you assign a role to a user or group on a resource, they receive the permissions associated with that role. For groups, all members receive the assigned permissions.
### Project Roles
The following table outlines the specific permissions for each role on projects:
| Permission | User | Editor | Admin |
| ------------------------------------------------------------- | --------------------- | --------------------- | --------------------- |
| **Read Access** | | | |
| Read project (view details, settings, configuration) | | | |
| Read secrets (names only, not values) | | | |
| Read environment classes (see which runners the project uses) | | | |
| Read prebuilds (view prebuild configurations and history) | | | |
| **Write Access** | | | |
| Update project (modify settings and configuration) | | | |
| Delete project | | | |
| Create prebuilds | | | |
| Update/delete prebuilds | | | |
| Create/update/delete secrets (full access including values) | | | |
| Create/update/delete environment classes (configure runners) | | | |
| **Admin Access** | | | |
| Grant access (share project with users and groups) | | | |
Editors can delete projects. Grant Editor access only to trusted team members who need full management capabilities.
### Runner Roles
The following table outlines the specific permissions for each role on runners:
| Permission | User | Admin |
| -------------------------------------------------------- | --------------------- | --------------------- |
| **Read Access** | | |
| Read runner (view details, status, configuration) | | |
| Read environment classes (view available machine types) | | |
| Read SCM integrations (view source control integrations) | | |
| Read/use LLM integrations (view and use AI/LLM features) | | |
| **Usage** | | |
| Create environments on this runner | | |
| Create agent executions (use AI agent features) | | |
| Create host authentication tokens | | |
| **Write Access** | | |
| Update runner (modify configuration and settings) | | |
| Delete runner | | |
| Create/update/delete environment classes | | |
| Create/update/delete SCM integrations | | |
| Create/update/delete LLM integrations | | |
| **Admin Access** | | |
| Grant access (share runner with users and groups) | | |
| Create runner tokens (for runner registration) | | |
| Access runner logs | | |
### Automation Roles
Automations can be shared with individual users or groups using the **Executor** role. See [Sharing Automations](/docs/ona/automations/sharing-automations) for details.
| Permission | Executor |
| -------------------------------------------------- | --------------------- |
| **Read Access** | |
| View automation (name, description, steps) | |
| View own executions | |
| View other users' executions | |
| **Usage** | |
| Run automation on accessible projects/repositories | |
| **Write Access** | |
| Edit automation | |
| Delete automation | |
| **Admin Access** | |
| Share automation with users and groups | |
Organization admins have full access to all automations, including the ability to create, edit, delete, share, and view all executions.
### Permission Inheritance
* **Direct and group access**: When a user has both direct access and group-based access to a resource, they receive the union of all permissions. The highest permission level applies.
* **Multiple groups**: When a user belongs to multiple groups with access to the same resource, they receive the union of all permissions from those groups.
* **Organization admins**: All org admins automatically have Admin permissions on all projects, runners, and automations, regardless of direct or group-based access.
* **Resource creators**: Project creators automatically become project admins and can share their projects with other users and groups.
## Best Practices
### Organize Groups by Function
Create groups that reflect how your team works:
* **By team**: "Frontend Team," "Backend Team," "DevOps"
* **By role**: "Developers," "Designers," "Product Managers"
* **By project**: "Mobile App Team," "API Team"
### Use Descriptive Names and Descriptions
Help others understand what each group is for:
* "Backend Engineers - API and Database Development"
* "Group 1"
### Start with Restrictive Access
Begin by sharing resources with specific users or groups. You can always expand access later:
1. Share with individual users for small teams or specific collaborators
2. Create groups for larger teams with similar access needs
3. Share resources with relevant users and groups
4. Adjust permissions based on feedback
5. Expand to organization-wide access if needed
### Review Access Regularly
Periodically review who has access to your resources:
* Check group memberships when people change roles
* Remove access for team members who no longer need it
* Update permission levels as responsibilities change
### Consider Runner Dependencies
Before restricting runner access:
1. Identify which projects use the runner
2. Ensure all project users also have runner access
3. Communicate changes to affected teams
### Use the Right Permission Level
Grant the minimum permissions needed:
* Most team members need **User** access
* Team leads or maintainers need **Editor** access
* Only a few people need **Admin** access
Review the detailed permissions in the "Roles and Permissions" section to understand what each role can do.
## FAQ
Yes, team members can belong to multiple groups. They'll receive the combined permissions from all their groups. If someone has User access through one group and Admin access through another, they effectively have Admin access.
All members lose access to resources that were shared exclusively with that group. Resources shared with other groups or with everyone in the organization remain accessible. The group deletion is permanent and cannot be undone.
This usually means you have access to the project but not to any of the runners it uses. Contact your organization admin to request runner access.
Verify that the resource is shared with the group, the person has runner access if needed, they've refreshed their browser, and check for any error messages.
They might have direct user access, be in another group with access, be included in "Everyone in Organization" access, or be an organization administrator.
Creating and managing groups requires organization admin permissions. Contact your organization admin if you need to manage groups.
Verify the project uses that runner, team members have project access, they're in the shared group, and no policies are blocking access.
Yes, open the Share dialog for any resource to see which users and groups have access and their permission levels. You can view groups to see their members.
Projects configured to use that runner will no longer be able to create environments using that runner's environment classes. If the project has other environment classes from different runners, those will still work. If it was the only runner, the project becomes unusable until you configure it with a new runner.
# Organization roles
Source: https://ona.com/docs/ona/organizations/organization-roles
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Organization roles let you delegate administrative and read-only responsibilities without granting full organization admin access. Assign these roles to [groups](/docs/ona/organizations/groups) to give team members role-specific capabilities across the organization.
## Available roles
| Role | Description |
| --------------------- | --------------------------------------------------------- |
| **Runners Admin** | Full admin access to all runners in the organization |
| **Projects Admin** | Full admin access to all projects in the organization |
| **Groups Admin** | Full admin access to all groups in the organization |
| **Automations Admin** | Full admin access to all automations (services and tasks) |
| **Insights Viewer** | Read-only access to Insights and project insights data |
| **Audit Log Reader** | Read-only access to audit logs |
| **Billing Viewer** | Read-only access to billing and usage information |
## How it works
When you assign an organization role to a group:
1. All group members receive the role's capabilities
2. Resource-scoped roles apply to existing and future resources where relevant
3. Removing the role revokes the related access
This differs from [Sharing resources](/docs/ona/organizations/sharing-resources), which grants access to specific projects or runners one at a time.
## Assign an organization role
Only organization admins can assign organization roles.
1. Go to **Settings → Members → Groups**
2. In the groups table, find the group you want to modify
3. Toggle the checkbox in the corresponding role column, such as **Runners Admin**, **Insights Viewer**, or **Billing Viewer**
The role is applied immediately when the checkbox is toggled.
## Permissions by role
### Runners Admin
Members of groups with this role can:
| Permission | Granted |
| ----------------------------------- | --------------------- |
| View all runners | |
| Create runners | |
| Update runner settings | |
| Delete runners | |
| Share runners with users and groups | |
| Manage environment classes | |
| Manage SCM and LLM integrations | |
| Access runner logs | |
### Projects Admin
Members of groups with this role can:
| Permission | Granted |
| ------------------------------------ | --------------------- |
| View all projects | |
| Create projects | |
| Update project settings | |
| Delete projects | |
| Share projects with users and groups | |
| Manage project secrets | |
| Configure environment classes | |
| Manage prebuilds | |
### Groups Admin
Members of groups with this role can:
| Permission | Granted |
| ---------------------------- | --------------------- |
| View all groups | |
| Create groups | |
| Update group settings | |
| Delete groups | |
| Add and remove group members | |
### Automations Admin
Members of groups with this role can:
| Permission | Granted |
| --------------------------------------- | --------------------- |
| View all automations | |
| Create automations | |
| Update automation settings | |
| Delete automations | |
| Share automations with users and groups | |
| View all execution history | |
This role does not grant webhook management permissions. Creating and managing [webhooks](/docs/ona/automations/webhooks) for automation triggers requires organization admin access.
### Insights Viewer
Members of groups with this role can:
| Permission | Granted |
| ---------------------------------------------------------- | --------------------- |
| View the Insights page | |
| View organization platform usage | |
| View Velocity and AI Adoption metrics for enabled projects | |
| Enable or disable project insights | |
Insights Viewers can only view data. Organization admins are required to enable project insights before Velocity and AI Adoption data appears.
### Audit Log Reader
Members of groups with this role can:
| Permission | Granted |
| ------------------------------------------- | --------------------- |
| View [audit logs](/docs/ona/audit-logs/overview) | |
| Query audit logs from the CLI | |
| Change organization settings | |
### Billing Viewer
Members of groups with this role can:
| Permission | Granted |
| ---------------------------------------------------------------------------------------- | --------------------- |
| View the [Billing](/docs/ona/billing/overview) page where available for the organization tier | |
| View the [Cost & Budgets](/docs/ona/billing/usage) page | |
| Export usage reports where export is available | |
| Change subscriptions, payment methods, top-ups, or team budgets | |
Billing Viewers can only view billing and usage information. Organization admins are required for billing changes, credit top-ups, and budget management.
## Use cases
**DevOps team manages infrastructure**: Assign Runners Admin to a "DevOps" group so they can create and configure runners without full org admin access.
**Team leads manage their projects**: Assign Projects Admin to a "Tech Leads" group so they can manage project settings and secrets across the organization.
**HR manages team membership**: Assign Groups Admin to an "HR" group so they can add and remove members from groups as people join or leave.
**Platform team manages automations**: Assign Automations Admin to a "Platform" group so they can create and maintain organization-wide automations.
**Security team reviews audit logs**: Assign Audit Log Reader to security or compliance staff who need audit history without organization admin access.
**Finance team reviews billing and usage**: Assign Billing Viewer to finance stakeholders who need read-only access to billing and usage data without payment or budget controls.
**Engineering leaders review delivery metrics**: Assign Insights Viewer to stakeholders who need read-only access to organization insights without project or runner administration permissions.
## Combining roles
A group can have multiple organization roles. For example, a "Platform Engineering" group might have both Runners Admin and Automations Admin roles.
When a user belongs to multiple groups with different roles, they receive the combined permissions from all their groups.
## Next steps
* [Create groups](/docs/ona/organizations/groups) to organize your team
* [Share resources](/docs/ona/organizations/sharing-resources) for fine-grained access control
* [Manage members](/docs/ona/organizations/manage-members) to invite teammates
# Archive timing
Source: https://ona.com/docs/ona/organizations/policies/archive-timing
Configure when stopped Enterprise environments move to Archived.
Configuring archive timing is available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Configure how long stopped Enterprise environments remain inactive before they move to Archived. Use this policy to align environment cleanup with your organization's retention requirements.
## Default archive timing
| Plan | Archive timing |
| ---------- | ---------------------------------------------- |
| Core | Fixed at 3 days |
| Enterprise | 3 days by default; configurable from 1-30 days |
Core organizations cannot change archive timing.
## Configure archive timing
Go to **Settings > Organization > Policies**. Under **Archive inactive environments**, select when stopped environments should move to Archived.
Available durations: 1 day, 2 days, 3 days, 5 days, 1 week, 2 weeks, 4 weeks, or 30 days.
## Effect on users
Stopped environments move to Archived after the configured period. Archived environments move to the archived environments view and can be unarchived or deleted.
Changing this policy affects scheduled archive lifecycle checks for stopped environments. Running environments are not archived.
See [Archive & auto-delete](/docs/ona/environments/archive-auto-delete) for the full environment lifecycle.
# Environment creation
Source: https://ona.com/docs/ona/organizations/policies/environment-creation
Restrict blank environment creation for members while still allowing projects and Git URLs.
Restrict blank environment creation to administrators while still allowing members to create environments from existing projects and Git URLs.
Useful when:
* You want members to start from a repository or project instead of an empty environment
* You want to reduce ad-hoc blank sessions without blocking normal Git-based work
* You want a lighter restriction than requiring project-based creation for all member environments
This policy affects members only, not admins.
## Configuration
Check **Only admins can start from scratch** in **Settings → Organization → Policies → Environment policies**.
## Effect on users
| Role | Capabilities |
| ----------- | ------------------------------------------------------------------------------------------ |
| **Members** | Can create environments from existing projects and Git URLs, but cannot start from scratch |
| **Admins** | Full access to create environments from scratch, projects, and Git URLs |
## Relationship to project creation
This policy is independent from [Project creation](/docs/ona/organizations/policies/project-creation):
* **Environment creation** blocks only blank environments for members
* **Project creation** is broader and requires members to create environments from existing projects
If you enable both policies, the project creation policy remains the stronger restriction for members.
# Maximum environment lifetime
Source: https://ona.com/docs/ona/organizations/policies/environment-lifetime
Set a maximum age for environments and optionally block restarting expired ones.
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Set a maximum age for environments. Environments that exceed this limit become non-compliant. Useful when:
* Enforcing security policies that require fresh environments (e.g., after a supply chain incident)
* Ensuring developers work with up-to-date base images and dependencies
* Meeting compliance requirements for environment rotation
Two controls available:
* **Maximum lifetime**: How long an environment can exist before it becomes non-compliant
* **Strict enforcement**: Whether non-compliant environments are blocked from restarting
## Configuration
Go to **Settings → Organization → Policies**. Select a duration from the dropdown. Only administrators can change this setting.
Available durations: 1 hour, 8 hours, 1 day, 3 days, 1 week, 2 weeks, 1 month, or no maximum.
Changes apply to existing and new environments. Changing the duration recalculates every existing environment's deadline from its creation time. Selecting **No maximum lifetime** clears existing deadlines. A global policy change replaces any lifetime previously set for an individual environment.
### Strict enforcement
When a lifetime is set, you can enable **strict enforcement** to prevent users from restarting non-compliant environments.
| Strict enforcement | Behavior |
| ------------------ | ---------------------------------------------------------------------------------------------- |
| **Off** (default) | Users see a warning when starting a non-compliant environment but can choose to restart anyway |
| **On** | Non-compliant environments are blocked from restarting. Users must create a new environment. |
The compliance banner shows how many environments are currently non-compliant and how many will become non-compliant within 24 hours. Click **Review environments** to open the environment inventory filtered to exceeded environments.
## Effect on users
Non-compliant environments display a status banner on the environment details page.
When an environment exceeds its lifetime and strict enforcement is off, users see a warning with the option to restart anyway or create a new environment.
When strict enforcement is on, users cannot restart a non-compliant environment. The modal shows the policy details and offers creating a new environment. Users can copy the details to share with an administrator for requesting an extension.
## Managing environments
Administrators can review and manage environment lifetimes from **Settings → Environments**.
The inventory shows each environment's lifetime expiry and compliance status. Use the **Exceeded** filter to find non-compliant environments.
To extend an individual environment's lifetime, click the **⋯** menu on an environment row and select **Update lifetime**.
You can extend or set a specific expiry date. Bulk updates are also available by selecting multiple environments. A later change to the organization-wide maximum lifetime replaces these individual deadlines.
## How it works
When an administrator sets a maximum lifetime:
1. **New environments** receive a lockdown timestamp equal to creation time plus the configured duration.
2. **Existing environments** receive a recalculated lockdown timestamp equal to their creation time plus the new duration.
3. **No maximum lifetime** clears the lockdown timestamp from existing environments and does not set one on new environments.
4. When an environment passes its lockdown timestamp, it becomes non-compliant.
5. Depending on strict enforcement, restarting is either warned or blocked.
# Auto-stop timeout
Source: https://ona.com/docs/ona/organizations/policies/environment-timeout
Limit auto-stop timeout options to control resource usage and costs.
Requires [Core plan](https://ona.com/pricing) or higher.
Limit how long environments can stay idle before auto-stopping. Useful when:
* Controlling cloud infrastructure costs from forgotten environments
* Ensuring resources are available for other team members
* Preventing "never timeout" settings that waste compute
## Configuration
Set the maximum auto-stop timeout to 30 minutes, 1 hour, 3 hours, 8 hours, or No max timeout.
## Effect on users
Users only see auto-stop timeout options up to the policy maximum. For example, with a 3-hour maximum, users can select 30 minutes, 1 hour, or 3 hours.
### Set a default auto-stop timeout
Available on the Core plan and higher. [Contact sales](https://ona.com/contact/sales) to learn more.
Each user can choose the auto-stop timeout applied when they create an environment:
1. Open **Account settings**.
2. Under **Preferences**, select a **Default auto-stop timeout**.
The available choices are 30 minutes, 1 hour, 3 hours, 8 hours, and Never. Choices above the organization's maximum auto-stop timeout are not available. If no preference is set, new environments use a 30-minute auto-stop timeout.
Changing this preference affects only environments created afterward. It does not update existing environments. An auto-stop timeout supplied when creating an individual environment overrides the user preference.
Users can also set an environment's auto-stop timeout from the CLI when creating or updating an environment:
```bash theme={null}
ona environment create https://github.com/org/repo --class-id --inactivity-timeout 1h
ona environment update --inactivity-timeout 3h
ona environment update --inactivity-timeout 0s
```
`0s` requests that auto-stop is disabled. The CLI is subject to the same plan and organization policy limits as the UI.
## When an environment is idle
An environment is **not idle** as long as any of the following are true:
* **Plain SSH session is open**: Any open SSH connection (terminal, SCP, SFTP, tunnels) prevents the environment from going idle, regardless of user interaction. Connection presence alone is enough. Note: VS Code Desktop opens an SSH connection to the environment, but that connection is excluded from activity tracking. VS Code uses its own activity signals instead.
* **VS Code is active (Desktop or Browser)**: The VS Code extension sends activity signals based on keyboard and mouse interaction. After a short period without interaction, VS Code stops signaling and the environment is considered idle.
* **JetBrains Gateway is active**: JetBrains sends activity signals based on keyboard and mouse interaction in the IDE. After approximately 5 minutes without interaction, JetBrains stops signaling and the environment is considered idle.
* **An agent is running**: The environment is not idle while an agent session is executing a task.
* **CLI keep-alive is active**: The `ona environment keep-alive` command prevents idle as long as a watched process is running (see [below](#keep-environment-alive-during-long-running-tasks)).
The following do **not** prevent an environment from going idle:
* Background processes running inside the environment (builds, servers, cron jobs)
* Port forwarding and shared/exposed port traffic (HTTP requests to forwarded ports)
* File system changes
* CPU or memory usage
Activity is tracked in 5-minute intervals. After the configured auto-stop timeout elapses, the environment may take several more minutes to stop. For example, with a 30-minute timeout, if you go idle at 2:00 PM the environment may stop around 2:35 PM.
### Common scenarios
| Scenario | Will it be considered idle? |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| VS Code open, idle (Desktop or Browser) | Yes. VS Code stops sending activity signals after a short period without keyboard or mouse interaction |
| JetBrains open, idle | Yes. JetBrains stops sending activity signals after approximately 5 minutes without keyboard or mouse interaction |
| Editor closed, terminal SSH session open | No. An open SSH connection prevents idle |
| All editor/SSH sessions closed, background build running | Yes. Background processes do not prevent idle |
| Laptop goes to sleep with VS Code open | Depends. If the sleep duration exceeds the configured timeout, the environment may auto-stop before VS Code can resume. JS timers freeze during sleep, so no activity signals are sent until the laptop wakes |
| Laptop goes to sleep with JetBrains open | Yes. JetBrains stops signaling during sleep, so the environment will auto-stop after the configured timeout |
## Keep environment alive during long-running tasks
For long-running tasks like simulations, builds, or data processing that may exceed the timeout, use the CLI `keep-alive` command to prevent automatic shutdown while a process is running.
```bash theme={null}
# Watch an existing process by PID
ona environment keep-alive --pid 1234
# Execute and watch a command
ona environment keep-alive -- python simulation.py
# Run in quiet mode (suppress output except errors)
ona environment keep-alive -q -- ./long-running-script.sh
```
| Flag | Description |
| ------------------ | -------------------------------------------------- |
| `--pid` | PID of an existing process to watch |
| `--interval` | Interval between activity signals (default: 5m) |
| `--source` | Source identifier for activity signals |
| `-q, --quiet` | Suppress output except errors |
| `--environment-id` | Environment ID (auto-detected inside environments) |
The command prevents the environment from going idle by sending signals every 5 minutes while the watched process is alive. When the process terminates, the command exits (propagating the exit code if a command was executed).
# Veto Exec executable policy
Source: https://ona.com/docs/ona/organizations/policies/executable-deny-list
Audit or block specific executables in organization environments with kernel-level enforcement.
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Veto Exec audits or blocks selected executables in organization environments.
Start with audit rules, review matches, then promote confirmed rules to block.
The public Veto Exec contract uses only `SecurityPolicy.spec.executables`.
Ports, files, block devices, and data are not part of this contract.
## Configure Veto in the dashboard
Open **Settings → Security** and find **Veto Executables**. Add an executable
path or bare name. Leave **Block** unchecked to audit the rule, or select it to
block execution, then save.
If your organization still uses an earlier Veto configuration, the form shows
those rules alongside current executable rules. Saving applies your edits and
moves the executable configuration to the organization's default
SecurityPolicy. Other SecurityPolicy sections are preserved.
An empty rule list has no executable effect. Saving changes only the executable
rules on the organization's default SecurityPolicy; other policy sections are
preserved. Restart a test environment to apply the changed default.
Preview supports policies whose rules all use the same effect. Save mixed Audit
and Block rules, then restart a test environment to verify them together.
## Create an audit-first policy
Save this policy as `veto-exec-policy.yaml`:
```yaml theme={null}
metadata:
name: Veto Exec audit-first
spec:
executables:
defaultEffect: EFFECT_ALLOW
rules:
- path: npx
effect: EFFECT_AUDIT
- path: /usr/bin/curl
effect: EFFECT_AUDIT
```
`defaultEffect` controls executables that do not match a rule. Omit it or set
it to `EFFECT_ALLOW`. Each rule must use `EFFECT_AUDIT` or `EFFECT_BLOCK`.
An executable rule cannot use `EFFECT_ALLOW`.
Each rule path must be one of these selector forms:
* An absolute path, such as `/usr/bin/curl`
* A bare executable name, such as `npx`
Bare names are expanded to concrete executable paths through runtime
discovery. Surrounding whitespace is ignored. Empty or whitespace-only
selectors, `.`, `..`, `./npx`, and relative paths such as `tools/npx` are
invalid after trimming.
Validate the file:
```bash theme={null}
ona organization security-policy init veto-exec-policy.yaml --validate-only
```
Create the policy in the active organization:
```bash theme={null}
ona organization security-policy create veto-exec-policy.yaml -o yaml
```
Creation stores an inactive policy definition. The CLI validates file input
before sending it, but the management plane's authoritative materializability
check runs on default assignment. An unassigned policy can later be rejected
when assigned.
Copy the returned policy ID and assign it as the organization default:
```bash theme={null}
ona organization security-policy set-default
```
If assignment rejects the stored definition, correct its executable default,
rule effects, or selectors, update it, and retry. Successful creation alone
does not prove that the policy can activate.
New environments receive the assigned policy. Restart an existing environment
to apply the current organization default. An already-running environment
keeps the policy from its last start.
## Review audit and block matches
During the interim rollout, organizations with the Veto Exec Audit Logs preview
enabled can review matching audit and block events in organization
[Audit Logs](/docs/ona/audit-logs/overview). Filter by the test environment while
you evaluate an audit rule:
```bash theme={null}
ona audit-logs --subject-id --subject-type environment
```
The action starts with `Veto Exec audited` or `Veto Exec blocked` and includes
the reported filename and full executable digest when available. Audit rules
allow execution. Block rules deny execution.
## Promote an audit rule to block
Change the confirmed rule in `veto-exec-policy.yaml`:
```yaml theme={null}
- path: npx
effect: EFFECT_BLOCK
```
Update the policy:
```bash theme={null}
ona organization security-policy update veto-exec-policy.yaml
```
Restart a test environment, run the executable, and confirm that execution is
denied. If the organization has the Veto Exec Audit Logs preview enabled, also
confirm that a `Veto Exec blocked` entry appears in Audit Logs.
## Understand Veto protection and content identity
Block rules do more than deny execution. Veto's built-in untouchable protection
also blocks direct reads and copies, writes, opens that could modify the file,
and writable shared-memory mappings of enrolled executable content. Veto
watches supported content and lifecycle changes, then refreshes the enrolled
content identity while preserving the rule's audit or block effect.
An executable path or bare name is a persistent selector that represents policy
intent, not a one-time hash input. Veto resolves matching executables and uses
their SHA-256 content identity for runtime decisions.
While a content hash remains enrolled, unchanged bytes retain the same decision
when they are:
* **Moved or renamed.** Changing the file's path does not change its content
identity.
* **Reached through a hard link.** The link resolves to the same unchanged
content.
* **Copied byte for byte.** An identical copy has the same content hash.
* **Invoked through a symlink.** A symlink to the same target reaches the same
unchanged content.
A later complete refresh of an exact-path selector may remove the old hash if
the selector no longer resolves. A bare-name selector may instead rediscover
matching basenames at new concrete paths.
Changing the executable's bytes creates a different content identity. Audit
rules allow and record activity. Veto's continuity handling is best effort: a
supported change is refreshed when Veto observes it, but filesystem changes
outside that observation flow are not guaranteed to preserve coverage without
a later complete refresh.
Different paths can resolve to identical executable content. If one resolved
hash has both audit and block rules, block wins for every path with that hash.
Choose hash-distinct executables when testing mixed audit and block rules.
Veto safelists Ona runtime binaries by content hash and cannot block them. If
Veto cannot resolve and hash a selector, the rule cannot enforce that content.
If the kernel cannot compute an executable hash for a launch because of an
internal failure, execution is allowed.
Blocking a shell interpreter such as `/bin/bash` also blocks scripts that use
that interpreter and can make an environment unusable. Test interpreter rules
in audit mode first.
## Roll back executable blocking
Change each blocked rule back to `EFFECT_AUDIT`, update the policy, and restart
affected environments. This keeps audit visibility and preserves other controls
in the organization's default SecurityPolicy.
```bash theme={null}
ona organization security-policy update veto-exec-policy.yaml
```
Clear the default assignment only when you intend to remove the entire
SecurityPolicy from newly created environments:
```bash theme={null}
ona organization security-policy set-default --clear
```
Restart affected environments to remove the cleared default policy. Clearing
the default removes every control in that SecurityPolicy, not only executable
rules. It does not change an already-running environment.
## Related controls
The [command deny list](/docs/ona/command-deny-list) applies pattern rules to Ona
Agent commands in userspace. Veto Exec applies content-hash decisions in the
kernel to executable launches from any process in the environment.
# Organization policies
Source: https://ona.com/docs/ona/organizations/policies/overview
Control resource usage, enforce consistency, and implement security restrictions across your organization.
Most policies require an [Enterprise plan](https://ona.com/pricing). Auto-stop timeout is available on Core and Enterprise.
Go to **Settings → Organization → Policies** to configure. Only administrators can access policies.
**Key behavior:**
* Changes take effect immediately for new actions
* Existing environments are not affected unless the policy governs a scheduled lifecycle action
## Available policies
| Policy | Purpose |
| ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| [Editor restrictions](/docs/ona/organizations/policies/editor-restrictions) | Standardize which editors and versions your team can use |
| [Auto-stop timeout](/docs/ona/organizations/policies/environment-timeout) | Limit auto-stop timeout options |
| [Environment limits](/docs/ona/organizations/policies/environment-limits) | Cap total and concurrent environments per user |
| [Maximum environment lifetime](/docs/ona/organizations/policies/environment-lifetime) | Set a maximum age for environments and optionally block restarting expired ones |
| [Archive timing](/docs/ona/organizations/policies/archive-timing) | Set when stopped Enterprise environments move to Archived |
| [Environment creation](/docs/ona/organizations/policies/environment-creation) | Restrict blank environment creation for members |
| [Project creation](/docs/ona/organizations/policies/project-creation) | Restrict project creation to admins; members must use existing projects |
| [Port sharing](/docs/ona/organizations/policies/port-sharing) | Control user-initiated port exposure from environments |
| [Web browser](/docs/ona/organizations/policies/web-browser) | Control whether members can open the built-in browser from environment pages |
| [Default image](/docs/ona/organizations/policies/default-image) | Set default devcontainer image |
| [Auto-delete](/docs/ona/organizations/policies/auto-delete) | Set retention period for archived environments |
| [Security agents](/docs/ona/organizations/policies/security-agents) | Deploy CrowdStrike Falcon to all environments |
| [Executable deny list](/docs/ona/organizations/policies/executable-deny-list) | Block specific executables from running in environments |
| [Command deny list](/docs/ona/command-deny-list) | Block specific commands from agent execution |
| [SCM tools](/docs/ona/organizations/policies/scm-tools) | Control agents' GitHub and GitLab access |
| [Automation limits](/docs/ona/automations/guardrails#organization-policy-limits) | Preview organization limits for selected Enterprise customers |
| [Restrict account creation to SCIM](/docs/ona/organizations/policies/scim-account-restriction) | Allow only SCIM-provisioned users to access the organization |
Looking for default environment image settings? See [Default image policy](/docs/ona/organizations/policies/default-image).
## Tracking changes
All policy changes are recorded in [audit logs](/docs/ona/audit-logs/overview), including who changed what and when.
## Best practices
* **Start gradually**: Begin with moderate limits and adjust based on usage patterns
* **Review regularly**: Check usage patterns quarterly or after team changes
* **Avoid over-restricting**: Use environment creation restrictions before requiring project-based creation for all member environments
# Restrict account creation to SCIM
Source: https://ona.com/docs/ona/organizations/policies/scim-account-restriction
Restrict organization access to users provisioned via SCIM.
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
When enabled, only users provisioned via [SCIM](/docs/ona/scim/overview) can access the organization. Users attempting to sign in via SSO without a SCIM-provisioned account are blocked.
Useful when:
* Centralizing account lifecycle management in your identity provider
* Ensuring every user in the organization has a corresponding directory entry
* Preventing access from users outside your provisioned scope, even if they can authenticate via SSO
## Prerequisites
* An active [SSO login provider](/docs/ona/sso/overview)
* An enabled [SCIM configuration](/docs/ona/scim/overview) linked to that SSO provider
The toggle is disabled until SCIM provisioning is configured and enabled.
## Configuration
1. Go to **Settings → Organization → Policies**
2. Toggle **Restrict Account Creation to SCIM**
Changes take effect immediately for new sign-in attempts. Existing members are not removed.
## Effect on users
| User type | Behavior |
| -------------------------------- | -------------------------------------------------------------- |
| SCIM-provisioned users | Sign in normally via the linked SSO provider |
| Non-provisioned users (SSO only) | Blocked from creating an account or joining the organization |
| Existing members | Retain access; remove via your IdP or by deactivating the user |
Before enabling, confirm that all users who need access are in scope of your SCIM provisioning. Users outside the provisioning scope will lose the ability to sign in to a new account, even with valid SSO credentials.
# Security agents
Source: https://ona.com/docs/ona/organizations/policies/security-agents
Deploy security agents like CrowdStrike Falcon to all organization environments.
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Deploy endpoint security agents to all environments automatically. Useful when:
* Meeting compliance requirements for endpoint detection and response (EDR)
* Monitoring development environments for threats
* Maintaining security visibility across your organization
**Available agents:** CrowdStrike Falcon
## CrowdStrike Falcon
Deploy the [CrowdStrike Falcon](https://www.crowdstrike.com/platform/falcon-sensor/) sensor as a sidecar container reporting to your CrowdStrike console. Falcon provides endpoint detection and response (EDR): threat detection, process monitoring, and malware prevention. It does not act as a firewall or enforce network policies.
There is no additional Ona charge for this integration. It is included in the Enterprise plan. You need your own CrowdStrike Falcon subscription.
### Prerequisites
* CrowdStrike Falcon subscription with container sensor support
* Access to the `falcon-sensor` container image in your CrowdStrike registry
* Customer ID (CID)
### Resource impact
The Falcon sensor runs on the environment VM alongside your workload. It starts asynchronously and does not increase environment startup time. Typical steady-state overhead:
* **CPU:** 1–3% (uses the BPF backend by default), with brief spikes during scans
* **Memory:** approximately 200–500 MB RAM
Exact figures depend on your Falcon sensor version and CrowdStrike policy settings (scan aggressiveness, prevention policies, etc.). Consult your CrowdStrike account team for precise numbers based on your configuration.
### Configuration
1. Go to **Policies** and toggle **Enable CrowdStrike Falcon**
2. Click **Settings**
3. Enter required information:
* **Customer ID (CID)**: Stored securely, not visible in secrets list
* **Falcon Sensor Image**: Full image reference to the **`falcon-sensor`** container image from your CrowdStrike registry (e.g., `123456789.dkr.ecr.us-east-1.amazonaws.com/falcon-sensor:7.18.0-17106`)
Use the **`falcon-sensor`** image, not `falcon-container`. CrowdStrike publishes multiple container images. `falcon-sensor` is the one required for VM-based deployments like Ona environments. Using `falcon-container` will cause the sensor to fail on startup.
4. (Optional) Expand **Advanced Options**:
* **Tags**: Comma-separated tags for Falcon console grouping
* **Additional Falcon Options**: Key-value pairs passed as `FALCONCTL_OPT_` environment variables to the sensor. Use this to set any [falconctl](https://falcon.crowdstrike.com/documentation/page/c24e4485/falcon-sensor-for-linux#falconctl) option.
5. Click **Save**
If your Falcon sensor image is hosted in a private registry (e.g., ECR, GCR, Artifactory), the environment needs credentials to pull it. Configure a [container registry authentication](/docs/ona/configuration/secrets/container-registry-secret) secret at the **organization level** so it applies to all environments, matching the org-wide scope of the security agent policy.
#### Configuring a proxy
The Falcon sensor does not use standard `HTTP_PROXY` / `HTTPS_PROXY` environment variables. If your environments route egress traffic through a proxy, configure it in **Advanced Options** → **Additional Falcon Options** with these keys:
| Key | Description | Example |
| ----- | -------------------------------------- | ---------------------------- |
| `APH` | Proxy host (hostname or IP, no scheme) | `proxy.internal.example.com` |
| `APP` | Proxy port | `3128` |
| `APD` | Disable proxy (`true` to disable) | `false` |
For example, to route Falcon traffic through `proxy.internal.example.com:3128`, add two entries in Additional Falcon Options:
* Key: `APH`, Value: `proxy.internal.example.com`
* Key: `APP`, Value: `3128`
### CLI configuration
```bash theme={null}
# View current configuration
ona organization security-agent get --organization-id
# Enable CrowdStrike Falcon
ona organization security-agent set \
--organization-id \
--crowdstrike-enabled \
--crowdstrike-image \
--crowdstrike-cid-secret-id
```
### Removal
To remove CrowdStrike Falcon from all environments:
1. Go to **Policies** and toggle off **Enable CrowdStrike Falcon**
2. Click **Save**
Existing environments will stop running the Falcon sensor on their next restart.
Via the CLI:
```bash theme={null}
ona organization security-agent set \
--organization-id \
--crowdstrike-enabled=false
```
### How it works
When enabled, the Falcon sensor deploys automatically as a privileged sidecar container to all environments. The container runs with full host-level visibility (`--pid=host`, `--net=host`, `--privileged`) using the BPF backend. These permissions are required for the sensor to monitor host-level processes and network activity.
Whether the sensor operates in detect-only mode (reporting threats) or prevention mode (blocking malicious processes) depends on your CrowdStrike Falcon console policy settings. Ona deploys the sensor; your CrowdStrike policies control its behavior.
Metadata tags are added automatically: `env_id/` and `org_id/`. These appear in your Falcon console for identifying which environment and organization each sensor belongs to.
### Effect on users
Users cannot view, modify, or disable the security agent. Only admins can configure it.
### Troubleshooting
| Issue | Solution |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| Sensor not in Falcon console | Verify CID, check network connectivity, review environment logs |
| Image pull failures | Verify registry auth, check image reference, confirm IAM permissions (ECR) |
| Sensor offline | Check network to CrowdStrike, verify CID is active, review sensor logs |
| Sensor fails on startup | Verify you are using the `falcon-sensor` image, not `falcon-container` |
| Sensor cannot reach CrowdStrike cloud | Configure proxy via `APH` and `APP` in Advanced Options (see [Configuring a proxy](#configuring-a-proxy)) |
# Web browser policy
Source: https://ona.com/docs/ona/organizations/policies/web-browser
Control whether members can open the built-in web browser from environment pages.
The built-in web browser is enabled by default on every tier. Enterprise organizations can edit this policy. [Contact sales](https://ona.com/contact/sales) to learn more.
Use the web browser policy to control whether members and agents can use the managed browser session inside environment pages. The policy is separate from editor access and port sharing.
Free, Core, and Enterprise organizations have the built-in browser enabled by default. Enterprise admins can disable it when the organization needs stricter controls for in-dashboard browser access.
## Configure the policy
Go to **Settings > Organization > Policies** and use **Allow Web Browser in Environments**.
| Organization tier | Default | Can change this policy |
| ----------------- | ------- | ---------------------- |
| Free | Enabled | No |
| Core | Enabled | No |
| Enterprise | Enabled | Yes |
When the policy is on:
* Members can open the Browser tab from environment pages.
* Members can preview local app ports in the Browser tab.
* Agents can use the `browse-web` built-in skill when you ask them to inspect or interact with a page.
* Browser screenshots and annotations can be sent to Ona from the Browser tab when Ona AI is enabled.
When an Enterprise admin turns the policy off:
* Browser actions are hidden on environment pages.
* The Browser tab is not offered in the dashboard.
* Ona does not expose the `browse-web` built-in skill to agents in that organization.
* Members cannot send browser screenshots or annotations from the Browser tab.
## Effect on related features
| Feature | Effect |
| -------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| Built-in browser panel | Disabled when the policy is off |
| `browse-web` built-in skill | Disabled when the policy is off |
| [VS Code Browser](/docs/ona/editors/vscode-browser) | Unaffected |
| [Port sharing](/docs/ona/organizations/policies/port-sharing) | Unaffected and controlled by its own policy |
| Editor availability | Unaffected and controlled by [Editor restrictions](/docs/ona/organizations/policies/editor-restrictions) |
Use the [port sharing policy](/docs/ona/organizations/policies/port-sharing) to control user-initiated shared ports. Use the web browser policy to control the in-dashboard browser session used by members and Ona.
## Security and port implications
The built-in browser runs in the environment and can reach services available from that environment, including local addresses such as `http://localhost:3000`. Keeping this policy enabled lets members and agents use that browser session for inspection and interaction.
Opening an app in the built-in browser does not publish that app's port to other users. Port sharing remains controlled by the [port sharing policy](/docs/ona/organizations/policies/port-sharing) and by each port's access level.
The browser uses a managed browser port so the dashboard can connect to the browser session. That managed port is separate from application ports that members open or share.
## Troubleshooting
Only Enterprise organizations can edit the web browser policy. Free and Core organizations can see the policy when it appears, but cannot change it.
This policy does not affect VS Code Browser. Use [Editor restrictions](/docs/ona/organizations/policies/editor-restrictions) to control which editors members can use.
# Service accounts
Source: https://ona.com/docs/ona/organizations/service-accounts
Service accounts are non-human identities that run automations independently of individual users. They decouple credentials from personal accounts, ensuring workflows continue when team members leave. Automated actions are attributed to the service account, making it straightforward to distinguish agent activity from human work.
Manage service accounts in **Settings → Members → Service Accounts**. Only admins can create or delete them.
## Create a service account
1. Go to **Settings → Members → Service Accounts**
2. Click **Create New Service Account**
3. Enter a name and optional description
4. Click **Create**
Service accounts expire 1 year from creation.
## Git authentication
Git authentication depends on the service account:
* The system-managed **Ona** service account uses the [Ona GitHub App](/docs/ona/integrations/configure-github) for GitHub.com repositories. You do not need to add a Personal Access Token (PAT). The App can access only repositories included in the GitHub App installation.
* User-created service accounts need PAT authentication to clone repositories, commit changes, and create pull requests.
* GitLab service accounts need PAT authentication.
### Add PAT authentication
1. Open the service account details page
2. Click **Add Git Authentication**
3. Select the **environment class** where the automation will execute
4. Choose your **Provider** (GitHub or GitLab)
5. Enter a **Personal Access Token** from your SCM
### Create a personal access token
**GitHub:**
1. Go to **Settings** > **Developer settings** > **Personal access tokens** > **Tokens (classic)**
2. Click **Generate new token**
3. Select scopes: `repo`, `read:user`, `user:email`, `workflow`
4. Copy the token
[GitHub documentation: Creating a personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic)
**GitLab:**
1. Go to **Preferences** > **Access Tokens**
2. Enter a name and expiration date
3. Select scopes: `api`, `read_repository`, `write_repository`
4. Click **Create personal access token**
5. Copy the token
[GitLab documentation: Personal access tokens](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html)
Store the token securely. You won't be able to see it again after creation.
## Commit attribution
When a service account uses a PAT to commit changes, the Git author email is determined by the account that owns the PAT. This affects how commits appear in your repository history and audit logs.
* **GitHub**: The PAT owner's primary email address is used for commit attribution
* **GitLab**: The PAT owner's email address is used, but email verification policies may apply (see below)
Organizations with audit or compliance requirements should ensure the PAT is created from an account with an appropriate email address.
## Platform-specific considerations
### GitLab email verification limitation
GitLab service accounts cannot have verified email addresses. If your organization requires verified emails for Git commits, you must use a dedicated real GitLab user account instead of a GitLab service account.
Many organizations enforce policies requiring all Git commits to use verified company domain emails (e.g., `@company.com`) for security and audit compliance. GitLab's native service accounts have a limitation that prevents this:
* GitLab service accounts can have custom email addresses assigned via API
* However, these emails remain in an **unconfirmed state** and cannot be verified
* Service accounts cannot sign in to the GitLab UI to complete email verification
* Even with a [verified domain](https://docs.gitlab.com/ee/user/enterprise_user/#manage-group-domains) configured in GitLab, service account emails are not automatically confirmed
This is a [known GitLab limitation](https://gitlab.com/gitlab-org/gitlab/-/issues/533775).
**Workaround for GitLab users with email verification policies:**
1. Create a dedicated real GitLab user account (e.g., `automation-bot@company.com`)
2. Verify the email address by signing in and completing verification
3. Generate a Personal Access Token from this dedicated user account
4. Use this PAT when configuring Git authentication for your Ona service account
This approach gives you the benefits of Ona service accounts (decoupled credentials, clear attribution) while satisfying GitLab's email verification requirements.
### GitHub
GitHub does not have the same email verification restrictions for automated commits. Personal Access Tokens work with any GitHub account type, including machine users and bot accounts. The system-managed Ona service account uses the Ona GitHub App instead of a PAT.
## Tool integrations
Service accounts can connect organization-enabled integrations separately from users. Use this for automations that need access to tools such as issue trackers, docs, observability systems, or Codex.
1. Open the service account details page
2. Go to the **Integrations** section
3. Find the integration
4. Click **Connect**
5. Complete the provider authorization flow
For Codex, Ona shows an OpenAI device authorization code. Sign in to ChatGPT, enter the code, and return to Ona when the dialog shows the account is connected.
Organization admins enable available integrations in **Organization Settings > Integrations**. If an integration is not listed for a service account, ask an admin to enable it first.
## Tokens
Service Account Tokens (SATs) are long-lived credentials for authenticating with the Ona API. Use them for automations, external scripts, or any programmatic access that needs to act as the service account.
Tokens can be created with a validity of 30 days, 60 days, 90 days, 1 year, or no expiry. Only organization admins can create tokens on behalf of a service account.
SATs can be used to start automations and perform read operations (GET/LIST) on the API. For additional use cases, contact the Ona team.
### Create a token
1. Open the service account details page
2. Go to the **Tokens** section
3. Click **New Token**
4. Enter a description and select a validity period (30 days, 60 days, 90 days, 1 year, or no expiry)
5. Click **Create**
6. Copy the token immediately. It won't be shown again
Store tokens in a secure secret manager (GitHub Secrets, HashiCorp Vault, AWS Secrets Manager). Never commit tokens to repositories.
### Use a token
Include the token in API requests as a Bearer token:
```bash theme={null}
curl -H "Authorization: Bearer $ONA_SA_TOKEN" \
https://app.gitpod.io/api/gitpod.v1.EnvironmentService/ListEnvironments
```
### Revoke a token
To revoke a token:
1. Open the service account details page
2. Go to the **Tokens** section
3. Click the delete icon next to the token
4. Confirm deletion
Suspending or deleting the service account also revokes all its tokens immediately.
## Secrets
Service accounts can have secrets attached. Secrets are injected into environments based on identity. When an environment runs as a service account, that service account's secrets are available.
This works the same way as [user secrets](/docs/ona/configuration/secrets/user-secrets). Organization and project secrets are also available, following the standard [precedence rules](/docs/ona/configuration/secrets/overview#secret-precedence).
### Create a secret
1. Open the service account details page
2. Go to the **Secrets** section
3. Click **New Secret**
4. Select the secret type:
* **Environment Variable**: injected as an environment variable
* **File**: mounted at a specified path
* **Container Registry**: credentials for private registries
5. Enter the secret details and click **Create**
For details on each secret type, see [Secrets](/docs/ona/configuration/secrets/overview).
## Using service accounts in automations
Use service accounts for shared or long-running workflows: scheduled jobs, pull request triggers, and automations that should outlive any single team member.
Organization Admins and Automations Admins can select active service accounts as Automation executors. Other users can run Automations only as themselves.
When creating or editing an automation:
1. Select the service account in **Run as**
2. Confirm its Git authentication is configured
3. Verify the service account can access the target repositories
The automation will use the service account's identity, Git credentials, and attached secrets for repository operations.
## Delete a service account
1. Navigate to **Settings → Members → Service Accounts**
2. Click on the service account name
3. Click **Delete Service Account**
4. Confirm deletion
A service account cannot be deleted if it is currently used by any automation. Update affected automations to use a different executor first.
## Next steps
* [Create an Automation](/docs/ona/automations/configure-automations) using a service account
* [Configure Pull Request Triggers](/docs/ona/automations/triggers/pullrequest) for event-driven automation
* [Set up Time-based Triggers](/docs/ona/automations/triggers/timebased) for scheduled jobs
# Manage teams
Source: https://ona.com/docs/ona/organizations/teams
Requires [Enterprise plan](https://ona.com/pricing). [Contact sales](https://ona.com/contact/sales) for access.
Teams are for **organizational reporting and cost management**, not access control. Use them to mirror your real-world structure, for example "Backend", "Mobile", or "Platform", so you can see where credit consumption goes and give each part of the organization its own spending target. To grant access to projects or runners, use [groups](/docs/ona/organizations/groups) instead. See [Groups vs. teams](/docs/ona/organizations/overview#groups-vs-teams) for a side-by-side comparison.
## Managing teams
Only organization admins can create, rename, or delete teams and manage team membership.
### Create a team
1. Go to **Settings → Members → Teams**
2. Click **New Team**
3. Enter a team name (3–80 characters, unique within the organization)
4. Optionally select members to add during creation
5. Click **Create**
### Add members
1. Open the team
2. Click **Add People**
3. Select members and click **Add**
A member can only be on one team per organization. If you add someone who is already on another team, move them from the original team first.
### Remove members
1. Open the team
2. Select members using the checkboxes
3. Click **Remove**
Removed members keep all their existing access to projects and runners. Team membership only affects how their usage is attributed going forward.
### Rename a team
1. Open the team or use the team card menu
2. Click **⋯** → **Edit**
3. Enter the new name and save
### Delete a team
1. Open the team
2. Click **⋯** → **Delete**
3. Confirm
Deleting a team removes its credit budget and ends per-team usage attribution for its members. Historical usage already attributed to the team is preserved in usage reports. Members keep all their access to projects and runners.
### Find members not on a team
The Teams tab shows a **Members not assigned to a team** section so you can spot who still needs to be placed. Use it as a checklist when rolling out teams across your organization.
## Roles within a team
Two roles apply inside a team. Both are assigned automatically. You do not manage them by hand.
| Role | Granted to | Can do |
| --------------- | ---------------------------------------- | -------------------------------------------------------- |
| **Team admin** | Organization admins, on every team | Rename the team, delete the team, add and remove members |
| **Team viewer** | Every organization member, on every team | View the team and see its member list |
Because every member is a viewer on every team, there is no concept of a private team. Team membership is visible across the organization.
## Per-team credit budgets
Each team can have a credit budget that you set on the **Cost & Budgets** page.
Budgets are **soft**: they are used for reporting and alerting only and are **not enforced** at usage time. Members on a team that has exceeded its budget can still create environments and run agents. The sum of all team budgets is allowed to exceed the organization's total credit grant.
Use budgets to:
* Give each team a planned credit allowance for the month
* Spot teams that are trending over their allowance early
* Compare planned vs. actual consumption across teams
### Set or change a team's budget
1. Go to **Settings → Cost & Budgets**
2. Switch the grouping to **Teams**
3. In the team's row, click the budget value (or **Set budget** if none is set)
4. Enter a credit amount and save
## Usage attribution
Once teams are in place, the **Cost & Budgets** page can group consumption by team:
* A daily credit chart broken down by team
* A table listing each team's consumption for the selected period, with a link to the team detail page
* CSV export, including the team column
Usage is attributed to whichever team a member belonged to **at the time the usage was metered**. Moving a member to a different team does not re-attribute their past usage.
Members who are not on any team appear under an "Unassigned" bucket in the chart and table.
## FAQ
No. Teams are for usage attribution and budgeting only. Access to projects and runners is controlled by sharing, either directly with users or through [groups](/docs/ona/organizations/groups).
No. Each member belongs to at most one team per organization. If you need overlapping membership for access purposes, use groups instead.
Past usage stays attributed to the team they were on at the time. Only new usage from the moment of the change is attributed to the new team.
Nothing is blocked. Budgets are soft and exist for reporting and alerting only. Members can continue to create environments and use Ona normally.
No. All members of an organization can see every team and its members.
# Regions and latency
Source: https://ona.com/docs/ona/runners/aws/aws-regions
Low network latency between dev environments and local machines ensures responsive IDE and terminal performance.
Region choice affects more than speed. It also influences data residency, user experience, and how well one runner can serve a distributed team.
## How to choose a region
Start with where your developers actually work, not just where your company is incorporated. For most teams, the best region is the one that minimizes round-trip latency for the majority of users.
If your team is spread across multiple continents, consider multiple runners instead of forcing everyone through one distant region.
## Recommended latency thresholds
| Latency | Experience | Recommendation |
| -------- | ---------- | ------------------------------------------------- |
| \< 70ms | Excellent! | Ideal for all development tasks |
| \< 120ms | Good | Suitable for most development work |
| \< 200ms | Ok | Users may notice some latency in IDE and terminal |
| > 200ms | Poor | Not recommended |
## Test latency before deploying
* [CloudPing](https://www.cloudping.cloud/aws)
* [AWS Latency Test](https://aws-latency-test.com/)
* `ping` or [httping](https://www.vanheusden.com/httping/) from command line
Test from where your users work. VPN affects results. Test with VPN if users connect through VPN.
## Practical guidance
* Prefer the closest region that also satisfies your compliance requirements.
* Test latency from actual developer locations before deployment.
* Re-test after VPN, proxy, or network policy changes.
* If one region is good for Europe but poor for North America, add another runner instead of accepting a globally slow default.
## Supported regions
### North America
* `us-east-1` (N. Virginia)
* `us-east-2` (Ohio)
* `us-west-1` (N. California)
* `us-west-2` (Oregon)
* `ca-central-1` (Canada Central)
### Europe
* `eu-west-1` (Ireland)
* `eu-west-2` (London)
* `eu-west-3` (Paris)
* `eu-central-1` (Frankfurt)
* `il-central-1` (Israel Central)
### Asia Pacific
* `ap-south-1` (Mumbai)
* `ap-southeast-1` (Singapore)
* `ap-southeast-2` (Sydney)
* `ap-northeast-1` (Tokyo)
### South America
* `sa-east-1` (São Paulo)
Need a different region? [Contact support](https://www.ona.com/contact/sales).
# Costs & budgeting
Source: https://ona.com/docs/ona/runners/aws/aws-runner-costs
Costs for runner infrastructure only. Does not include development environment costs or license fees.
AWS pricing varies by region. Check [AWS pricing](https://aws.amazon.com/pricing/) for current rates.
## Billable resources
| Resource | Purpose |
| ---------------- | ------------------------------------------------------------------------------------------------------------------ |
| ECS Service | Manages environments |
| DynamoDB Table | Stores environment state |
| S3 Bucket | Docker and image caches |
| ECR Repository | Dev container image cache (when [enabled](/docs/ona/runners/devcontainer-image-cache)) |
| EBS Snapshots | [Base snapshot cache](/docs/ona/runners/aws/base-snapshots) for eligible Enterprise runners |
| CloudWatch Logs | Runner task logs |
| Lambda Functions | CloudFormation Custom Resources for network configuration and capacity provider lifecycle (negligible / free tier) |
## Base snapshot costs
For eligible Enterprise AWS runners, Ona maintains [base snapshots](/docs/ona/runners/aws/base-snapshots) to reduce environment startup time.
* Ona meters each initial build, daily refresh, retry, and replacement as normal environment usage while its background environment runs.
* AWS bills the EC2 instance and EBS volume used during each build as part of your cloud bill.
* AWS bills EBS snapshot storage. Ona does not meter snapshot storage separately.
Ona normally keeps one compatible successful snapshot for each eligible runner. During a refresh, the previous snapshot remains available until its replacement is ready, so both snapshots can appear on the AWS bill for a short time.
## Baseline costs
* **ECS task**: Less than \$8/month (covered by AWS free tier), fixed regardless of environment count
* **Other services** (DynamoDB, S3, CloudWatch): Less than 1% of runner cost
## Viewing costs in AWS Cost Explorer
### Runner costs
1. Open AWS Cost Explorer
2. Group by **Usage Type**
3. Filter by CloudFormation stack name (find it at **Settings → Runners**):
* Tag: `aws:cloudformation:stack-name`
* Or: `aws:ecs:clusterName`
### Environment costs
Filter by environment ID using the **Name** tag with value `gitpod-environment-`. Find the ID via **Copy ID** in environment details.
## EC2 instance tagging
EC2 instances inherit tags from the CloudFormation template for cost allocation and access control.
**Add tags:**
1. Open your runner's CloudFormation stack
2. Select **Update** → **Use current template**
3. Add tags in format `Key=Value`
4. Complete the update
Tag changes don't apply to the running ECS task immediately. Force a new deployment: **ECS → Clusters → your cluster → Service → Update → Force new deployment**.
# Base snapshots for AWS runners
Source: https://ona.com/docs/ona/runners/aws/base-snapshots
Understand how Ona uses automatic base snapshots to reduce startup time on Enterprise AWS runners.
Available on the Enterprise plan. Base snapshots require a supported, up-to-date AWS runner. [Contact sales](https://ona.com/contact/sales) to learn more.
Base snapshots are an automatic startup optimization for environments on AWS runners. Ona builds and refreshes them in the background. Developers and organization administrators do not need to create, schedule, or monitor them.
A base snapshot stores a prepared copy of the organization's [default image](/docs/ona/organizations/policies/default-image), its container image layers, and runner-managed startup assets. A new environment can restore this cached data instead of downloading it again. The workspace, repository, user configuration, and project setup still start fresh.
Organizations with large default images or self-hosted registries with limited pull throughput benefit most because new environments avoid repeatedly pulling and unpacking the image.
## How base snapshots reduce startup time
Ona maintains one base snapshot for each eligible AWS runner in an organization:
1. Ona starts a system-owned build environment on the runner.
2. The build environment pulls the organization default image and prepares shared startup assets.
3. Ona removes environment-specific data and credentials, then stores the prepared data disk as an Amazon EBS snapshot.
4. New environments on the same runner can restore the EBS snapshot as a best-effort cache.
If a project has a compatible [prebuild](/docs/ona/projects/prebuilds), the prebuild takes precedence because it contains project-specific state. Otherwise, Ona uses a compatible base snapshot when one is available.
## Eligibility is automatic
Ona creates base snapshots when all of these conditions are met:
* The organization is on the Enterprise plan.
* The environment uses a supported, up-to-date AWS runner with [dual disk](/docs/ona/runners/dual-disk) support.
* The organization has configured a [default image](/docs/ona/organizations/policies/default-image).
* The runner has at least one enabled environment class with a valid data disk size.
Eligibility applies at the organization level. Administrators do not enable individual runners or environments.
## Refreshes and fallback happen in the background
Ona builds the first snapshot after the runner becomes eligible and refreshes it once per day. Every daily refresh creates a new EBS snapshot, even when the default image reference has not changed. This picks up changes behind mutable image tags.
Changing the default image reference also starts a replacement build. The previous compatible snapshot remains available until the replacement succeeds. Ona then deletes the older snapshot.
Base snapshots are a best-effort cache. If no compatible snapshot is available, a lookup or restore fails, or a runner becomes ineligible, environment creation continues through the normal cold-start path. The environment pulls the default image and may take longer to start, but the missing cache does not prevent creation. Ona retries failed background builds without administrator action.
## Private images require organization credentials
If the default image is in a private registry, configure its credentials as an organization-level [container registry secret](/docs/ona/configuration/secrets/container-registry-secret). Base snapshot build environments receive organization registry credentials only. They do not receive project secrets, user secrets, repository contents, or project automations.
For Amazon ECR, you can use runner-native IAM authentication. Create the registry secret at **Settings → Organization → Secrets** and configure the environment role permissions described in [AWS ECR with IAM authentication](/docs/ona/configuration/secrets/container-registry-secret#using-aws-ecr-with-iam-authentication).
## Snapshots remain scoped to their runner
The EBS snapshot remains in the AWS account and region that host the runner. Ona uses it only for environments on that runner. It contains reusable container and startup data, not workspace or user data.
## Usage and AWS costs
Each base snapshot build runs as a background environment. Ona meters the time that it runs as normal environment usage. This includes initial builds, daily refreshes, retries, and replacements after an administrator resets cached image data. System-owned build environments do not count toward per-user running-environment limits.
The underlying compute and storage resources run in your AWS account. AWS bills the EC2 and EBS resources used during a build and the EBS snapshot storage. Ona does not meter base snapshot storage separately. See [AWS runner costs and budgeting](/docs/ona/runners/aws/aws-runner-costs#base-snapshot-costs).
At steady state, Ona keeps one compatible successful base snapshot for each eligible runner. The current and replacement snapshots can coexist during a refresh. Ona deletes the older snapshot after the replacement is ready.
## Administrators normally do not manage base snapshots
Ona monitors snapshot availability and build health. There is no base snapshot status page in the dashboard. Organization administrators only see the **Reset cached image data** action described below.
When troubleshooting, organization administrators can use `gitpod base-snapshot list`, `gitpod base-snapshot get `, and `gitpod base-snapshot logs ` to inspect snapshots. The command group also provides `create `, `cancel `, and `delete ...` controls. Run `gitpod base-snapshot --help` for command usage, and use lifecycle controls in coordination with Ona support.
Organization administrators can [reset cached image data](/docs/ona/organizations/policies/default-image#reset-cached-image-data) when stale or incorrect cached data must be removed. Resetting deletes completed base snapshots across the organization's eligible AWS runners. Ona builds replacements automatically, and environments use the cold-start path until replacements are ready.
## FAQ
No. Base snapshot selection and cold fallback happen during environment creation. The environment has the same fresh workspace and configuration either way.
No. Base snapshots cache organization-wide default-image data for one AWS runner. [Prebuilds](/docs/ona/projects/prebuilds) add project-specific workspace and setup state, while the [Dev Container image cache](/docs/ona/runners/devcontainer-image-cache) caches built Dev Container images. Ona can use these startup optimizations together.
No. Base snapshot lifecycle operations and the **Reset cached image data** control use your organization's active management-plane domain. Registry image references and credentials do not change when the organization uses a custom domain.
## Troubleshooting
The runner may not have a usable base snapshot yet. This can happen after first enablement, a default-image change, a cache reset, or a failed refresh. Ona continues with a cold start and builds or retries the snapshot in the background.
For a private default image, confirm that its container registry credential is an organization secret and that the AWS environment role can pull the image. If cold starts continue beyond the next daily refresh, contact Ona support with the organization and runner names.
# Capacity planning
Source: https://ona.com/docs/ona/runners/aws/capacity-planning
Size your AWS runner infrastructure before deployment. The two factors that determine your configuration are the number of environments you plan to run and how many will be active at the same time.
## Runner sizes
The AWS runner CloudFormation template includes a `RunnerSize` parameter that controls the runner control plane infrastructure. Choose the size that matches your expected workload.
| | Small | Large |
| ------------------------------- | --------------------------- | ------------------------------ |
| **Total environments** | Up to 5,000 | 5,000+ |
| **Concurrent running** | Up to 300 | 300+ |
| **Availability zones** | 2 | 3 or more |
| **EC2 subnet** | `/20` per AZ (4,096 IPs) | `/16` per AZ using CGNAT range |
| **LB subnet** | `/28` per AZ | `/28` per AZ |
| **Management plane connection** | NAT gateway or VPC endpoint | VPC endpoint (PrivateLink) |
| **Managed metrics** | Recommended | Required |
| **Runner scaling** | Not needed | Recommended |
If you are unsure which size to start with, choose small. You can switch to large later by updating the `RunnerSize` CloudFormation parameter without redeploying the stack.
The `RunnerSize` parameter controls the runner control plane (orchestrator, proxy, cache). It does not affect the size of environment VMs. Environment VM sizing is configured through [environment classes](/docs/ona/runners/aws/environment-classes).
## Small runner
Set `RunnerSize` to `small` in the CloudFormation template. This is the default.
The small configuration supports up to 5,000 total environments and 300 running at the same time. It is the right starting point for most deployments.
### Infrastructure provisioned
| Component | Specification |
| ------------------- | ------------------------ |
| Runner Fargate task | 1 vCPU, 3 GB memory |
| Proxy Fargate task | 0.5 vCPU, 1 GB memory |
| ECS host instance | c6i.large (2 vCPU, 4 GB) |
| Cache (MemoryDB) | db.t4g.small |
### Network layout
Use 2 availability zones with one EC2 subnet and one load balancer subnet per AZ.
Stopped environments are stopped EC2 instances. Stopped instances retain their private IP address, so your subnets must be large enough to hold all environments, not only the ones that are running.
| Runner Name | Region | AZs | EC2 Subnet | LB Subnet | Environment Capacity |
| ----------- | --------- | --- | --------------- | ------------ | -------------------- |
| us-east | us-east-1 | 2 | /20 (4,096 IPs) | /28 (16 IPs) | \~8,187 |
Select your region based on [recommended latency thresholds](/docs/ona/runners/aws/aws-regions#recommended-latency-thresholds). If this works for you, proceed to [setup](/docs/ona/runners/aws/setup).
**Capacity formula:** (Subnet IPs per AZ x Number of AZs) - \~5 management IPs
| EC2 Subnet | IPs per AZ | With 2 AZs | With 3 AZs |
| ---------- | ---------- | ---------- | ---------- |
| /21 | 2,048 | \~4,091 | \~6,139 |
| /20 | 4,096 | \~8,187 | \~12,283 |
| /19 | 8,192 | \~16,379 | \~24,571 |
### Multi-region example
Each runner is deployed into a single AWS region and a single AWS account. To serve users in multiple regions, deploy one runner per region.
| Runner Name | Region | AZs | EC2 Subnet | LB Subnet | Environment Capacity |
| ----------- | --------- | --- | --------------- | ------------ | -------------------- |
| us-east | us-east-1 | 2 | /20 (4,096 IPs) | /28 (16 IPs) | \~8,187 |
| us-west | us-west-2 | 2 | /21 (2,048 IPs) | /28 (16 IPs) | \~4,091 |
| europe | eu-west-1 | 2 | /21 (2,048 IPs) | /28 (16 IPs) | \~4,091 |
### Connectivity
The runner must reach the Ona management plane and several AWS services. For small deployments, a NAT gateway provides the simplest path. See [Networking](/docs/ona/runners/aws/networking) for all connectivity options.
For lower latency and to avoid NAT gateway data processing charges, you can connect the runner to the management plane over [PrivateLink](/docs/ona/runners/aws/networking#creating-vpc-endpoints). This is optional for small runners but recommended if your subnets already use VPC endpoints for AWS services.
## Large runner
Set `RunnerSize` to `large` in the CloudFormation template.
The large configuration is designed for deployments that exceed 5,000 total environments or 300 concurrent running environments. It provisions more CPU, memory, and cache capacity for the runner control plane, and supports horizontal scaling of the runner service.
Heavy agent workloads (many concurrent AI agent sessions) increase runner control plane load independently of environment count. If you observe high CPU utilization on the runner Fargate task with fewer than 5,000 environments, switch to large.
### Infrastructure provisioned
| Component | Specification |
| ------------------- | ------------------------------------------------------------------- |
| Runner Fargate task | 4 vCPU, 16 GB memory per replica (2 to 5 replicas with autoscaling) |
| Proxy Fargate task | 2 vCPU, 4 GB memory |
| ECS host instance | c6i.2xlarge (8 vCPU, 16 GB) |
| Cache (MemoryDB) | db.t4g.medium |
To enable horizontal scaling, set `EnableRunnerScaling` to `true` in the CloudFormation template. The runner service starts with 2 replicas and scales up to 5 based on CPU and memory utilization.
### Network layout
Use 3 or more availability zones. At this scale, spreading environments across more AZs is important for two reasons:
1. **Instance capacity.** When many environments start at the same time, EC2 `RunInstances` calls concentrate per AZ. More AZs reduce the chance of hitting `InsufficientInstanceCapacity` in any single zone.
2. **Fault tolerance.** Losing one AZ still leaves two or more zones operational, which matters when hundreds of environments are running.
For EC2 subnets, use a CGNAT range (`100.64.0.0/10`). EC2 subnets do not need to be routable because environments connect outbound through NAT or proxy. CGNAT provides a large address space without consuming your organization's routable IP allocation.
| Runner Name | Region | AZs | EC2 Subnet | LB Subnet | Environment Capacity |
| ----------- | ------------ | --- | ----------------------------------- | ------------ | -------------------- |
| production | eu-central-1 | 3 | /16 (65,536 IPs) per AZ using CGNAT | /28 (16 IPs) | \~196,603 |
A `/16` per AZ is generous. Size the subnets based on your expected peak, with room for growth. The key point is that CGNAT ranges are free to use and expanding subnets after deployment is complex.
### Management plane connection
For large runners, connect to the Ona management plane over PrivateLink instead of routing through the public internet.
Without PrivateLink, all runner-to-management-plane traffic traverses a NAT gateway. At high environment counts, this adds latency and incurs NAT gateway data processing charges (\$0.045/GB). PrivateLink keeps this traffic within the AWS network.
**If you use `app.gitpod.io`:** Create a VPC endpoint to the Ona management plane service. See [Networking: VPC endpoints](/docs/ona/runners/aws/networking#creating-vpc-endpoints) for setup instructions. When private DNS is enabled on the endpoint, `app.gitpod.io` resolves to private IPs inside your VPC and the runner connects directly over PrivateLink.
**If you use a [custom domain](/docs/ona/custom-domain):** The custom domain page describes how to set up a VPC endpoint and load balancer for access to the management plane through your domain. The custom-domain path already goes through your Network Load Balancer. To also keep the runner's API traffic private, use split-horizon DNS so the runner VPC resolves your custom domain to the private load-balancer endpoint instead of the public DNS record or external proxy path. See [Route runner API traffic privately](/docs/ona/custom-domain#26-route-runner-api-traffic-privately) for the supported DNS patterns.
### Managed metrics
Enable [Ona managed metrics](/docs/ona/runners/managed-metrics) on large runners. Managed metrics give the Ona team visibility into runner health, which enables proactive detection of resource exhaustion, elevated error rates, and degraded performance. Without metrics, Ona cannot identify issues until you report them.
### Reserved capacity
At this scale, consider [EC2 Capacity Reservations](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-capacity-reservations.html) or [Savings Plans](https://docs.aws.amazon.com/savingsplans/latest/userguide/what-is-savings-plans.html) for your most-used environment instance types. Reservations guarantee instance availability in your AZs and reduce costs compared to on-demand pricing.
## Planning steps
### 1. Select regions
Choose [AWS regions with optimal latency](/docs/ona/runners/aws/aws-regions) for your users. Plan subnet sizes for each region before deploying.
### 2. Estimate environments per region
For each region, estimate the maximum number of environments including:
* Current users and expected growth
* Peak concurrent usage patterns
* Agent and automation workloads (each agent session runs in its own environment)
### 3. Choose availability zones
| Deployment size | Recommended AZs |
| -------------------------------- | --------------- |
| Small (up to 5,000 environments) | 2 |
| Large (5,000+ environments) | 3 or more |
One EC2 subnet and one load balancer subnet are required per AZ.
### 4. Plan subnet sizes
#### EC2 subnets
Each environment uses one IP address. Stopped environments are stopped EC2 instances and retain their IP address, so plan for the total number of environments (running and stopped), not only the concurrent running count.
| Consideration | Details |
| ------------------- | -------------------------------------------------------- |
| IP per environment | 1 (retained while stopped) |
| Management overhead | \~5 IPs |
| Minimum size | /28 (10 environments) |
| Capacity formula | (Subnet IPs per AZ x Number of AZs) - \~5 management IPs |
EC2 subnets can use non-routable CIDR ranges. For large deployments, use CGNAT (`100.64.0.0/10`) to avoid IP exhaustion. Plan generously because expanding subnets after deployment is complex.
For public subnets, enable [auto-assign public IP](https://docs.aws.amazon.com/vpc/latest/userguide/subnet-public-ip.html).
#### Load balancer subnets
For the Network Load Balancer:
* Must be routable from your internal network
* `/28` (16 IPs) is sufficient for all deployment sizes
* One subnet per AZ
* Does not affect environment capacity
## Next steps
* [Setup guide](/docs/ona/runners/aws/setup): Deploy your AWS runner with CloudFormation
* [Networking](/docs/ona/runners/aws/networking): Connectivity options and VPC endpoint configuration
* [Environment classes](/docs/ona/runners/aws/environment-classes): Configure VM sizes for your environments
* [Costs and budgeting](/docs/ona/runners/aws/aws-runner-costs): Estimate AWS infrastructure costs
# AWS access requirements
Source: https://ona.com/docs/ona/runners/aws/detailed-access-requirements
Configure your firewall and network security groups to allow outbound connections to these endpoints for Ona to function properly.
**Proxy support**: Enterprise runners support HTTP proxy configuration. Add `.internal`, `169.254.169.254`, `169.254.170.2`, `app.gitpod.io`, and `.amazonaws.com` to NO\_PROXY. See [proxy configuration](/docs/ona/runners/aws/setup#http-proxy-configuration).
## Ona services
### Management plane
* `https://app.gitpod.io`
* `https://app.ona.com`
## VS Code
Server downloads and extension marketplace:
* `https://update.code.visualstudio.com/api/commits/stable/server-linux-x64-web`
* `https://update.code.visualstudio.com/api/commits/stable/server-linux-arm64-web`
* `https://update.code.visualstudio.com/commit:*/server-linux-x64/stable`
* `https://update.code.visualstudio.com/commit:*/server-linux-arm64/stable`
* `https://*.vscode-unpkg.net`
* `https://marketplace.visualstudio.com`
* `https://*.gallerycdn.vsassets.io`
* `https://*.prss.microsoft.com`
* `https://*.vscode-gitpod-cdn.com` (required for VS Code Web functionality)
* `https://vscode.gitpod.io` (required for VS Code Web functionality)
## JetBrains
IDE downloads and services:
* `https://www.jetbrains.com`
* `https://download.jetbrains.com`
* `https://download-cf.jetbrains.com`
* `https://download-cdn.jetbrains.com`
* `https://data.services.jetbrains.com`
* `https://plugins.jetbrains.com`
* `https://downloads.marketplace.jetbrains.com`
* `https://account.jetbrains.com`
See also: [JetBrains network requirements](/docs/ona/editors/jetbrains#network-access-requirements)
## Release artifacts
Updates, CLI binaries, and agent components are served from `app.gitpod.io/releases/*` (same domain as the control plane):
* `https://app.gitpod.io/releases/ec2/stable/manifest.json`
* `https://app.gitpod.io/releases/ec2/stable/supervisor-amd64.xz`
* `https://app.gitpod.io/releases/ec2/stable/gitpod-ec2-runner-enterprise-fargate-private-ecr.template.json`
* `https://app.gitpod.io/releases/cli/stable/manifest.json`
* `https://app.gitpod.io/releases/cli/stable/gitpod-linux-amd64`
* `https://app.gitpod.io/releases/cli/stable/gitpod-linux-amd64.exe`
* `https://app.gitpod.io/releases/cli/stable/gitpod-linux-amd64.sha256`
* `https://app.gitpod.io/releases/cli/stable/gitpod-linux-arm64`
* `https://app.gitpod.io/releases/cli/stable/gitpod-linux-arm64.sha256`
* `https://app.gitpod.io/releases/vscode/releases/*/vscode-remote.vsix`
* `https://app.gitpod.io/releases/vscode/releases/*/vscode-agent-amd64`
* `https://app.gitpod.io/releases/vscode/releases/*/vscode-agent-arm64`
* `https://app.gitpod.io/releases/jetbrains/releases/*/jetbrains-agent-amd64`
* `https://app.gitpod.io/releases/jetbrains/releases/*/jetbrains-agent-arm64`
## Container registries
**Default Dev Container image:**
* `https://mcr.microsoft.com/devcontainers/base:2.0.4-noble`
**AWS Private ECR (runner images):**
Runner images are pulled from private ECR. This requires access to three AWS endpoints (replace `` with your AWS region):
* `https://api.ecr..amazonaws.com` - ECR API
* `https://.dkr.ecr..amazonaws.com` - Docker registry protocol
* `https://s3..amazonaws.com` - Image layer storage
For private network deployments, see [Networking](/docs/ona/runners/aws/networking#vpc-endpoints-reference) to configure PrivateLink access to these services.
## Your infrastructure
### Runner proxy domain
The runner must be able to reach its own configured domain over HTTPS. It periodically verifies DNS resolution and TLS connectivity by requesting `https:///_health`. Blocking this egress causes the runner to report degraded status.
* `https://` (the domain you configured during setup)
### SCM and SSO providers
Configure access to your providers:
* GitHub, GitLab, Bitbucket URLs
* SSO provider URLs (Okta, Azure AD, etc.)
## Optional services
### Prometheus remote write
* Your metrics endpoint URL (HTTPS 443)
### Additional container registries
**Common registries:**
* `https://index.docker.io`
* `https://registry-1.docker.io`
* `https://auth.docker.io`
* `https://ghcr.io`
* Your private registry URLs (HTTPS 443)
## AWS services
Replace `` with your AWS region and `` with your AWS account ID.
### Instance metadata
* **Endpoint**: `169.254.169.254`
* **Protocol**: HTTP (80)
### Regional APIs
* `https://ec2..amazonaws.com`
* `https://.dkr.ecr..amazonaws.com`
* `https://s3..amazonaws.com`
* `https://ssm..amazonaws.com`
* `https://sts..amazonaws.com`
* `https://dynamodb..amazonaws.com`
* `https://cloudformation..amazonaws.com`
* `https://secretsmanager..amazonaws.com`
* `https://logs..amazonaws.com`
* `https://acm..amazonaws.com`
* `https://ecs..amazonaws.com`
* `https://ecs-agent..amazonaws.com`
* `https://ecs-telemetry..amazonaws.com`
* `https://ssmmessages..amazonaws.com`
* `https://ec2messages..amazonaws.com`
* `https://elasticloadbalancing..amazonaws.com`
## AMI requirements
If your AWS Organization restricts AMI access, ensure your account can launch from these AMIs:
### Required AMIs
| AMI Name | Owner Account ID | Owner | Purpose |
| -------------------------------------------- | ---------------- | ----- | ------------------------ |
| `gitpod/images/gitpod-next/ec2-runner-ami-*` | `995913728426` | Ona | Development environments |
### Allowlisting by owner account ID
Allow by **Owner Account ID** rather than specific AMI ID. This ensures automatic access to new versions and security patches.
Configure your AWS Organization's AMI access policies to:
1. Allow Owner Account ID `995913728426` (Ona)
2. Test that your deployment account can launch from these AMIs
### Test AMI access
```bash theme={null}
# List available AMIs from Ona's account (replace us-east-1 with your region)
aws ec2 describe-images --region us-east-1 --owners 995913728426 --filters "Name=name,Values=gitpod/images/gitpod-next/ec2-runner-ami-*"
```
If you encounter AMI access issues, contact your AWS administrator to update AMI access policies.
## SSH domain aliases
Ona uses aliases like `.gitpod.remote`, `.gitpod.environment`, and `.ona.environment` for SSH connectivity.
These are SSH configuration aliases (not internet domains) that map to EC2 instance IP addresses:
* The Ona CLI automatically updates your SSH config with actual instance IPs
* Provides clean identifiers instead of complex AWS hostnames like `ec2-18-184-202-80.region.compute.amazonaws.com`
* When you connect via SSH or VS Code, your SSH client resolves the alias to the actual IP
# Environment classes
Source: https://ona.com/docs/ona/runners/aws/environment-classes
Environment classes define computing resources (instance type, disk size) for development environments.
## Default classes
| Class Name | Instance Type | Disk Size | Spot Instance |
| ---------------- | ------------------------- | --------- | ------------- |
| Small | M6i Large (m6i.large) | 45 GB | No |
| Regular | M6i XLarge (m6i.xlarge) | 80 GB | No |
| Large | M6i 2XLarge (m6i.2xlarge) | 100 GB | No |
| Extra Large | M6i 8XLarge (m6i.8xlarge) | 200 GB | No |
| Extra Large Spot | M7i 8XLarge (m7i.8xlarge) | 200 GB | Yes |
| GPU Large | G5 4XLarge (g5.4xlarge) | 300 GB | No |
| GPU Large Spot | G5 4XLarge (g5.4xlarge) | 300 GB | Yes |
## Create custom classes
1. Go to **Organization settings → Environment Classes** (under AWS runners)
2. Click **Add Environment Class**
3. Configure:
* **Name** and **Description**
* **Disk size**: Storage capacity
* **Instance type**: Any x64 EBS-enabled type (e.g., t3.medium, m5.large, c5.xlarge)
## Modify classes
Only name and description can be edited after creation. To change disk size or instance type, create a new class and optionally disable the old one.
## Disable classes
When disabled:
* Existing environments continue running
* No new environments can use this class
## Use classes
Select environment classes when creating environments manually or via project configuration.
## Supported instance types
Requirements:
* EBS volume support
* X64 architecture (Intel or AMD)
ARM-based instance types (e.g., Graviton) are not currently supported.
Examples by category:
* **General purpose**: `t3.medium`, `t3.large`, `m5.large`, `m5.xlarge`
* **Compute optimized**: `c5.large`, `c5.xlarge`
* **Memory optimized**: `r5.large`, `r5.xlarge`
* **Storage optimized**: `i3.large`, `d2.xlarge`
### Considerations
* **Regional availability**: Not all types available in every region
* **Quotas**: Ensure sufficient AWS account quota
* **Costs**: Pricing varies by instance family
* **Instance generations**: Newer generations offer better price-performance
* **Storage**: Choose instances with more storage than RAM
See [AWS EC2 Instance Types](https://aws.amazon.com/ec2/instance-types/) for details.
## Spot instance reclamation
When using AWS Spot instances, Ona automatically handles reclamation:
1. The environment on the reclaimed instance is terminated
2. A new instance is provisioned automatically
3. The EBS volume is reattached to the new instance
4. All data on the EBS volume is preserved
## GPU / CUDA workloads
To run NVIDIA CUDA workloads, select the **Data Science** environment class (`g5.4xlarge`) when creating an environment or configuring a project. See the [gpu-demo repository](https://github.com/ona-samples/gpu-demo) for a working `devcontainer.json` and Dockerfile with CUDA support via [containers.dev features](https://containers.dev/features).
## Best practices
* Standardize classes across your organization
* Limit to classes teams actually need
* Create specialized classes for specific workloads (data processing, frontend, etc.)
* Review usage patterns and adjust regularly
# Networking
Source: https://ona.com/docs/ona/runners/aws/networking
The AWS runner runs as a Fargate service in your VPC. The ECS cluster contains three services: the runner orchestrator, a proxy for routing traffic to environments, and AWS ADOT for metrics export (when configured). Each Fargate task gets its own elastic network interface (ENI) in your subnets, so the subnets must provide a path to the AWS services the runner depends on.
## Required AWS service endpoints
The runner must reach the following AWS services over HTTPS (port 443):
| Service | Endpoint | Purpose |
| ------------------- | --------------------------------------- | ------------------------------------------------ |
| **Secrets Manager** | `secretsmanager..amazonaws.com` | Retrieve runner token and configuration secrets |
| **CloudWatch Logs** | `logs..amazonaws.com` | Ship runner and container logs |
| **ECR API** | `api.ecr..amazonaws.com` | Authenticate and authorize container image pulls |
| **ECR Docker** | `*.dkr.ecr..amazonaws.com` | Pull runner container images |
| **S3** | `s3..amazonaws.com` | Download ECR image layers |
Replace `` with your AWS region.
These connections must be **direct TCP**. The runner verifies reachability by dialing each endpoint directly, bypassing any HTTP proxy. If any endpoint is unreachable, the runner reports a degraded network status.
## Connectivity options
Choose the method that fits your network architecture.
### NAT gateway
Route traffic from private subnets to AWS service public endpoints via a NAT gateway in a public subnet.
**When to use:** Private subnets that already have a NAT gateway for general internet access.
No additional configuration is needed. As long as the Fargate task subnets have a route to a NAT gateway, the runner can reach AWS service endpoints over their public addresses.
### Internet gateway (with public IP)
Assign a public IP directly to the Fargate task and route traffic through an internet gateway.
**When to use:** Public subnets without NAT gateway, or development/test environments where simplicity is preferred.
To enable this, set the **Assign Public IP** CloudFormation parameter to `true` when deploying the runner stack. ECS assigns a public IP to each Fargate task ENI when this parameter is enabled.
If your Fargate task subnets use an internet gateway but you do **not** enable public IP assignment, the tasks will have no outbound connectivity and the runner will fail to start.
### VPC endpoints (AWS PrivateLink)
Route traffic to AWS services over private IPs within your VPC, without traversing the public internet.
**When to use:** Private subnets with no internet access, or when security policy prohibits public internet egress.
See [VPC endpoints reference](#vpc-endpoints-reference) below for the full list of endpoints and creation instructions.
**Cost consideration**: VPC endpoints incur additional AWS charges (\~\$7.20/month per endpoint per AZ plus data processing fees). See [AWS PrivateLink pricing](https://aws.amazon.com/privatelink/pricing/) for details.
### Transit gateway / VPC peering / VPN
Route traffic to AWS service endpoints through a transit gateway, VPC peering connection, or VPN tunnel to a VPC that has access to the services.
**When to use:** Hub-and-spoke network architectures where AWS service access is centralized in a shared-services VPC.
Ensure the route tables on the Fargate task subnets include routes to the AWS service endpoint IP ranges through the transit gateway or peering connection.
## Automatic connectivity checks
The runner automatically checks connectivity to all required endpoints on startup and every 5 minutes. Results are reported to the management plane as a network readiness status.
Each endpoint check:
1. Resolves the hostname via DNS
2. Opens a direct TCP connection on port 443
The report classifies each endpoint's access type:
| Access type | Meaning |
| ------------------ | ----------------------------------------------------------------------------- |
| `vpc_endpoint` | DNS resolved to private IPs. Traffic stays within the VPC |
| `nat_gateway` | DNS resolved to public IPs, task has no public IP. Traffic routes through NAT |
| `internet_gateway` | DNS resolved to public IPs, task has a public IP. Traffic routes through IGW |
You can view the readiness status in the runner details on the Ona dashboard.
## VPC endpoints reference
If your network does not allow public internet egress, create VPC endpoints to give the runner infrastructure private access to AWS services. The table below lists all endpoints required by the runner stack, including those used by the ECS control plane, CloudFormation, environment VMs, and the runner services themselves.
### Prerequisites
Before creating VPC endpoints, ensure:
* Your VPC has both **DNS hostnames** and **DNS resolution** enabled
* You have the VPC ID, subnet IDs, and security group IDs ready
* You are creating endpoints in the same region as your runner deployment
You can enable DNS settings in the VPC Console under Actions > Edit VPC settings.
### Required interface endpoints
Replace `` with your AWS region.
| Service | VPC Endpoint Service Name |
| -------------------------- | --------------------------------------------- |
| **EC2** | `com.amazonaws..ec2` |
| **ECR API** | `com.amazonaws..ecr.api` |
| **ECR Docker** | `com.amazonaws..ecr.dkr` |
| **SSM** | `com.amazonaws..ssm` |
| **STS** | `com.amazonaws..sts` |
| **CloudFormation** | `com.amazonaws..cloudformation` |
| **Secrets Manager** | `com.amazonaws..secretsmanager` |
| **ECS** | `com.amazonaws..ecs` |
| **ECS Agent** | `com.amazonaws..ecs-agent` |
| **ECS Telemetry** | `com.amazonaws..ecs-telemetry` |
| **SSM Messages** | `com.amazonaws..ssmmessages` |
| **EC2 Messages** | `com.amazonaws..ec2messages` |
| **CloudWatch Logs** | `com.amazonaws..logs` |
| **IAM** | `com.amazonaws..iam` |
| **Elastic Load Balancing** | `com.amazonaws..elasticloadbalancing` |
| **ACM** | `com.amazonaws..acm` |
IAM is a global service, but its VPC endpoint is created as a regional interface endpoint. See the [AWS documentation on creating an IAM VPC endpoint](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam_vpc_endpoint_create.html) for setup instructions.
### Required gateway endpoints
| Service | VPC Endpoint Service Name |
| ------------ | --------------------------------- |
| **S3** | `com.amazonaws..s3` |
| **DynamoDB** | `com.amazonaws..dynamodb` |
We recommend the S3 **gateway endpoint** because it is free of charge. Gateway endpoints are configured on route tables rather than ENIs. If you need DNS-based private resolution for S3 (e.g. for compliance reasons), use an interface endpoint instead.
Gateway endpoints (S3, DynamoDB) are configured differently than interface endpoints. See the [AWS documentation on gateway endpoints](https://docs.aws.amazon.com/vpc/latest/privatelink/gateway-endpoints.html) for details.
### Creating VPC endpoints
#### Using AWS CLI
```bash theme={null}
# Replace vpc-xxx, subnet-xxx, and sg-xxx with your actual IDs
aws ec2 create-vpc-endpoint \
--vpc-id vpc-xxx \
--service-name com.amazonaws.vpce.us-east-1.vpce-svc-08de744d433e60ff2 \
--vpc-endpoint-type Interface \
--subnet-ids subnet-xxx subnet-xxx \
--security-group-ids sg-xxx \
--private-dns-enabled \
--service-region us-east-1
```
For more CLI options and examples, see the [AWS CLI reference for create-vpc-endpoint](https://docs.aws.amazon.com/cli/latest/reference/ec2/create-vpc-endpoint.html).
#### Using AWS PowerShell
```powershell theme={null}
# Replace vpc-xxx, subnet-xxx, and sg-xxx with your actual IDs
New-EC2VpcEndpoint `
-VpcId "vpc-xxx" `
-ServiceName "com.amazonaws.vpce.us-east-1.vpce-svc-08de744d433e60ff2" `
-VpcEndpointType "Interface" `
-SubnetId @("subnet-xxx", "subnet-xxx") `
-SecurityGroupId @("sg-xxx") `
-PrivateDnsEnabled $true `
-ServiceRegion "us-east-1"
```
For more PowerShell options and examples, see the [AWS PowerShell reference for New-EC2VpcEndpoint](https://docs.aws.amazon.com/powershell/v4/reference/items/New-EC2VpcEndpoint.html).
#### Using AWS Management Console
1. **Navigate to VPC Console**
* Open the [AWS VPC Console](https://console.aws.amazon.com/vpc)
* Select "Endpoints" from the left navigation
2. **Create Endpoint**
* Click "Create endpoint"
* **Name tag** (optional): Enter a descriptive name like `ona-management-plane`
* **Service type**: Select "Endpoint services that use NLBs and GWLBs"
3. **Service Settings**
* **Service name**: Enter `com.amazonaws.vpce.us-east-1.vpce-svc-08de744d433e60ff2`
* **Enable Cross Region endpoint**: Check this box to connect across regions (Note: For **us-east-1** region, leave this unchecked)
* **Region**: Select us-east-1 as the region
* Click "Verify service" to confirm the service is available
4. **Network Settings**
* **VPC**: Select the same VPC where your runner is deployed
* **Enable DNS name**: Check this box to enable private DNS names (this allows `app.gitpod.io` to resolve to the endpoint)
* **Subnets**: Choose private subnets in available AZs (can be the same subnets as your EC2 runner instances)
* **Security groups**: Select or create a security group that allows HTTPS traffic (port 443, inbound). Include the runner security group and the security group for environment access (you can find these in the Output section of the Runner CloudFormation template).
5. **Create and Verify**
* Click "Create endpoint"
* Wait for the endpoint status to become "Available"
For detailed instructions on creating and managing VPC endpoints, see the [AWS documentation on creating interface endpoints](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html).
#### Key configuration settings
When creating interface endpoints:
* **Enable private DNS names**: This allows AWS service hostnames to resolve to your VPC endpoint's private IP addresses
* **Subnets**: Select subnets in multiple availability zones for high availability
* **Security groups**: Configure to allow HTTPS (443) traffic from your runner subnets
**us-east-1 region specific**: When creating VPC endpoints in the us-east-1 region, disable cross-region support. This is due to availability zone mapping differences between AWS accounts that can prevent endpoint creation. The endpoint only needs to exist in one AZ within your VPC. Clients in other AZs can still reach it via DNS.
### Security group configuration
Your VPC endpoint security group needs these rules:
**Inbound Rules:**
* **Type**: HTTPS (443)
* **Source**: Your runner subnets CIDR or the security group attached to your runner instances
* **Description**: Allow runner access to AWS services
**Outbound Rules:**
* **Type**: All traffic
* **Destination**: 0.0.0.0/0 (or keep the default outbound rule)
## Troubleshooting
1. **Check subnet route tables:** Verify the subnets assigned to the Fargate service have routes to the required endpoints (via NAT gateway, internet gateway, transit gateway, or VPC endpoints).
2. **Check security groups:** The ECS task security group must allow **outbound HTTPS (port 443)** to the AWS service endpoints. The default `AllowAllOutbound` rule covers this.
3. **Check VPC endpoint configuration** (if using PrivateLink):
* Ensure **private DNS** is enabled on interface endpoints
* Ensure the endpoint security group allows inbound HTTPS from the Fargate task subnets
* If using an S3 gateway endpoint, ensure it is associated with the correct route tables
4. **Check public IP assignment** (if using internet gateway):
* Verify the [`AssignPublicIp` CloudFormation parameter](/docs/ona/runners/aws/setup#network-configuration) is set to `true`
* Verify the subnet has an internet gateway attached and a route to `0.0.0.0/0` via the IGW
5. **DNS resolution:** From a test instance in the same subnet, verify endpoints resolve correctly:
```bash theme={null}
nslookup secretsmanager..amazonaws.com
nslookup logs..amazonaws.com
nslookup api.ecr..amazonaws.com
```
If using VPC interface endpoints, these should resolve to private IPs within your VPC CIDR.
If using an S3 **gateway endpoint** (recommended), `nslookup s3..amazonaws.com` will still resolve to public IPs. This is expected. Gateway endpoints route traffic via route table entries, not DNS overrides. Verify connectivity by checking that the gateway endpoint is associated with the correct route tables. If using an S3 **interface endpoint** instead, DNS should resolve to private IPs.
* **DNS resolution fails**: Verify DNS hostnames and DNS resolution are enabled on your VPC
* **Connection timeouts**: Check security group rules allow HTTPS (443) from runner subnets
* **Endpoint creation fails in us-east-1**: Disable cross-region support when creating the endpoint
* **Service unavailable**: Ensure the endpoint is in "Available" state and private DNS is enabled
For additional troubleshooting, see the [AWS PrivateLink troubleshooting guide](https://docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints-troubleshooting.html).
# AWS runners
Source: https://ona.com/docs/ona/runners/aws/overview
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Use AWS runners when your team wants Ona to execute inside your AWS environment instead of on Ona-managed infrastructure.
This is the right fit when you need:
* source code and execution to stay in your AWS network
* tighter control over networking, IAM, and regional placement
* integration with existing platform, compliance, or network controls
If you want the fastest path to a working setup, start with [Ona Cloud](/docs/ona/runners/ona-cloud) instead.
## What the runner includes
An AWS runner gives Ona an execution layer inside your VPC.
The deployment includes:
* a runner orchestrator running on AWS-managed infrastructure you control
* environment provisioning for development environments and agent runs
* repository access and secret handling inside your AWS boundary
* network and IAM integration with the rest of your AWS estate
## Getting started
Head over to the [Setup guide](/docs/ona/runners/aws/setup) for prerequisites and step-by-step deployment instructions.
## Related pages
* [Setup](/docs/ona/runners/aws/setup) - Prerequisites and CloudFormation deployment
* [Networking](/docs/ona/runners/aws/networking) - Connectivity options and VPC endpoints
* [Capacity planning](/docs/ona/runners/aws/capacity-planning) - Instance types, concurrency, and scaling
* [Detailed access requirements](/docs/ona/runners/aws/detailed-access-requirements) - IAM permissions and network access
* [Configuring repository access](/docs/ona/runners/configuring-repository-access) - Source control integration
# Setup AWS runner
Source: https://ona.com/docs/ona/runners/aws/setup
Deploy your AWS Runner using CloudFormation. This guide walks through creating the runner in Ona, configuring the CloudFormation template, deploying, and verifying connectivity.
## Prerequisites
1. **AWS account** with permissions to deploy CloudFormation stacks and create IAM resources. See [detailed access requirements](/docs/ona/runners/aws/detailed-access-requirements).
2. **Capacity planning** for instance types and concurrency. See [capacity planning](/docs/ona/runners/aws/capacity-planning). Ensure sufficient EC2 service quotas.
3. **AMI allowlisting** if your organization restricts AMI usage. Allowlist owner account `995913728426` (AMI: `gitpod/images/gitpod-next/ec2-runner-ami-*`).
4. **VPC and subnets** in 2-3 availability zones. EC2 subnets for environment instances, load balancer subnets routable from your users' network. Review [networking](/docs/ona/runners/aws/networking) to choose a connectivity option.
5. **Domain name** that you control with DNS modification capabilities.
6. **SSL/TLS certificate** in ACM with SANs for `yourdomain.com` and `*.yourdomain.com`.
## Create runner in Ona
1. In the Ona dashboard, go to **Settings > Runners** and click **Set up a new runner**
2. Select **AWS** as the provider
3. Enter a **name**, select the **AWS region**, and click **Create**
The dashboard generates a CloudFormation link with your **Runner ID**, **Exchange Token**, and **API Endpoint** pre-filled.
Runners are regional and can only launch environments in the AWS region they are deployed in. For multi-region support, set up multiple runners in different regions. The region cannot be changed after deployment.
## CloudFormation template deployment
Ensure you are signed into the correct AWS account, then click **Open AWS CloudFormation** in the runner details page. This opens the AWS console with the template pre-loaded.
Most parameters are auto-filled. The template is organized into the parameter groups described below.
### Ona configuration
The Runner ID, Exchange Token, and API Endpoint are auto-generated. Do not modify these values.
| Parameter | Description | Required |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| **Runner ID** | Unique identifier for your runner | ✅ Yes (auto-filled) |
| **Exchange Token** | Authentication token for the runner | ✅ Yes (auto-filled) |
| **API Endpoint** | Ona management plane API URL | ✅ Yes (auto-filled) |
| **Runner Size** | Infrastructure size. Start with `small` for most deployments. Switch to `large` if you experience performance issues under heavy agent load. | ✅ Yes |
| **Cache Engine** | Data store for AI execution. `MemoryDB` (default) or `ElastiCache`. Use ElastiCache only if MemoryDB is unavailable in your region. | ✅ Yes |
### Network configuration
VPC and subnet settings for the runner and environments.
| Parameter | Description | Example Value | Default | Required |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | ------- | -------- |
| **VPC** | The VPC where the runner will be deployed | `vpc-12345abcd` | N/A | ✅ Yes |
| **Availability Zones** | AZs for high availability (select 2-3) | `us-east-1a, us-east-1b` | N/A | ✅ Yes |
| **EC2 Instances Subnet** | Private subnets for EC2 environment instances. Should match the number of AZs. | `subnet-123abc, subnet-456def` | N/A | ✅ Yes |
| **Load Balancer Subnets** | Subnets for the load balancer, routable from your users' network. Should match the number of AZs. | `subnet-123abc, subnet-456def` | N/A | ✅ Yes |
| **Assign Public IP** | Assign a public IP address to the runner tasks. Set to `true` if using an Internet Gateway for outbound connectivity. Set to `false` if using a NAT gateway or VPC endpoints. | `true` | `false` | ✅ Yes |
If your runner subnets use an **internet gateway** for outbound connectivity (no NAT gateway, no VPC endpoints), you **must** set **Assign Public IP** to `true`. Without a public IP, the runner tasks will have no outbound connectivity and the runner will fail to start.
**Recommendations:**
* Select 2-3 Availability Zones for high availability
* **EC2 subnets**: use private subnets sized for your expected workload
* **Load balancer subnets**: must have CIDR ranges routable from your users' network
* Ensure connectivity from user locations via VPN, Direct Connect, or Transit Gateway
### DNS configuration
Domain name, SSL certificate, and load balancer visibility.
| Parameter | Description | Example Value | Required |
| ---------------------------- | ------------------------------------ | ---------------------------------------------------------- | -------- |
| **Load Balancer Visibility** | `internal` or `internet-facing` | `internal` | ✅ Yes |
| **Domain Name** | Your domain name for runner access | `yourdomain.com` | ✅ Yes |
| **Certificate ARN** | ARN of your SSL certificate from ACM | `arn:aws:acm:us-east-1:123456789012:certificate/abc123...` | ✅ Yes |
**Load balancer visibility options:**
* **internal**: load balancer is only accessible from within your VPC (recommended for private deployments)
* **internet-facing**: load balancer is accessible from the public internet (requires public subnets)
### Advanced configuration
The settings below are for organizations with additional network or security requirements. Most deployments do not need these.
#### Load balancer ingress control
| Parameter | Description | Example Value |
| ------------------------- | ----------------------------------------------------------------------------------------------- | -------------- |
| **Custom Security Group** | Security group to attach to the load balancer. Must allow incoming traffic on port 443 (HTTPS). | `sg-abcdef123` |
By default, the CloudFormation template creates a security group that allows all traffic (`0.0.0.0/0`) to ports 80 and 443 on the load balancer. To restrict ingress to specific source IP ranges or security groups, provide your own security group.
#### HTTP proxy configuration
For environments behind corporate firewalls or proxies:
| Parameter | Description | Example Value |
| --------------- | --------------------------------------------- | ---------------------------------------------------------------------- |
| **HTTP Proxy** | HTTP proxy server URL | `http://proxy.company.com:8080` |
| **HTTPS Proxy** | HTTPS proxy server URL | `https://proxy.company.com:8080` |
| **All Proxy** | All-protocol proxy server URL | `http://proxy.company.com:8080` |
| **No Proxy** | Comma-separated list of hosts to bypass proxy | `.internal,169.254.169.254,169.254.170.2,app.gitpod.io,.amazonaws.com` |
When configuring a proxy, `No Proxy` must include at minimum: `.internal`, `169.254.169.254`, `169.254.170.2`, `app.gitpod.io`, and `.amazonaws.com`.
**When proxy changes take effect:**
* **Runner infrastructure**: immediately after CloudFormation update
* **Content initialization**: after environment restart
* **Devcontainer**: after rebuild
* **Docker in Docker**: after container recreation
#### Custom CA certificate
If your network uses a corporate proxy or internal services with certificates signed by a private Certificate Authority, configure the runner to trust your CA.
| Parameter | Description | Example Value |
| -------------------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------- |
| **Custom CA Trust Bundle** | PEM-encoded CA certificate bundle, provided as an S3 URL, HTTPS URL, or SSM dynamic reference | `s3://gitpod-myorg/shared/ca-bundle.pem` |
Custom CA certificates work in runner, content init (SCM), and docker pull operations. However, they are **not supported** in devcontainer and devcontainer image build phases. You must add CA certificates to your images for these use cases.
This is commonly needed alongside [HTTP proxy configuration](#http-proxy-configuration) when the proxy performs TLS inspection with a corporate CA.
There are three ways to provide the certificate:
**1. Store the certificate in an S3 bucket (recommended)**
This avoids the EC2 user data size limit and is the recommended approach for bundles with multiple certificates.
1. Create an S3 bucket with a name starting with `gitpod-` (e.g. `gitpod-myorg`)
2. Upload your `.pem` file to the bucket (e.g. `s3://gitpod-myorg/shared/ca-bundle.pem`)
```
s3://gitpod-myorg/shared/ca-bundle.pem
```
3. Ensure the bucket is accessible by the runner's IAM role (buckets prefixed with `gitpod-` are allowed by default)
4. Set the `CustomCATrustBundle` parameter to the S3 URL
**2. Reference the certificate from an HTTPS endpoint**
If your CA bundle is hosted on an internal web server accessible from the runner's VPC, provide the URL directly:
```
https://internal-pki.example.com/ca-bundle.pem
```
**3. Store the certificate in SSM Parameter Store**
Use CloudFormation dynamic references to retrieve certificates from AWS SSM Parameter Store. For syntax details, see [SSM Parameter Store](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references-ssm.html) documentation.
```
{{resolve:ssm:/ona/ca-cert}}
```
Use an S3 URL if your CA bundle contains multiple certificates. SSM dynamic references embed the full certificate into EC2 user data, which has a 16 KB limit, and can fail with `"User data is limited to 16384 bytes"`. See [Custom CA certificate troubleshooting](/docs/ona/runners/aws/troubleshooting-runners#custom-ca-certificate-issues) for related issues.
## Deploy
1. Review all parameters
2. Check the box acknowledging CloudFormation will create IAM resources
3. Click **Create stack**
Deployment typically takes 20-25 minutes. Monitor progress in the CloudFormation **Events** tab.
## Configure DNS
After deployment, get the load balancer DNS name from the CloudFormation **Outputs** tab (look for **LoadBalancerDNS**).
Create DNS records pointing to this value for both the root domain and wildcard.
### Route 53
Create alias records pointing to your Network Load Balancer:
| Type | Name | Alias Target |
| ----- | ------------------ | --------------------------------------------- |
| **A** | `yourdomain.com` | Alias to Network Load Balancer in your region |
| **A** | `*.yourdomain.com` | Alias to Network Load Balancer in your region |
### Other DNS providers
Create CNAME records pointing to your load balancer DNS:
| Type | Name | Value | TTL |
| ----- | ------------------ | ------------------------------------------------------------- | --- |
| CNAME | `yourdomain.com` | `internal-LoadBa-XXXXX-123456789.us-east-1.elb.amazonaws.com` | 300 |
| CNAME | `*.yourdomain.com` | `internal-LoadBa-XXXXX-123456789.us-east-1.elb.amazonaws.com` | 300 |
DNS changes typically propagate within 5-60 minutes.
## Verify deployment
Once DNS propagates, verify the runner is healthy:
```bash theme={null}
curl -k https://yourdomain.com/_health
nslookup yourdomain.com
```
Check the runner status in the Ona dashboard under **Settings > Runners** to confirm it shows as connected.
## Next steps
* [Configure repository access](/docs/ona/runners/configuring-repository-access) - Set up access to your Git repositories
* [Environment classes](/docs/ona/runners/aws/environment-classes) - Configure compute resources for environments
* [Dev container image cache](/docs/ona/runners/devcontainer-image-cache) - Speed up environment starts
* [Model access](/docs/ona/agents/llm-providers/overview) - Configure OpenAI direct API or AWS Bedrock Mantle access
* [Troubleshooting](/docs/ona/runners/aws/troubleshooting-runners) - Common problems and diagnostic steps
# Troubleshooting AWS runners
Source: https://ona.com/docs/ona/runners/aws/troubleshooting-runners
Troubleshoot AWS runner issues.
Network misconfigurations are the most common cause of issues. See [access requirements](/docs/ona/runners/aws/detailed-access-requirements) first.
## CloudFormation stack fails
**Symptoms:** `ROLLBACK_COMPLETE` or `ROLLBACK_IN_PROGRESS` with errors like `Parameter validation failed: parameter value for EC2RunnerInstancesSubnet does not exist.`
**Fix:** Ensure you select a VPC, at least one availability zone, and subnets across multiple AZs.
## Runner task fails
**Symptoms:**
* `CREATE_FAILED` with `ECS Deployment Circuit Breaker was triggered`
* `ResourceInitializationError` in task logs
* Cannot pull images or access AWS services
**Fix:**
* Verify VPC has Internet Gateway or NAT Gateway
* Update route tables (public → IGW, private → NAT)
* For private subnets, add VPC endpoints for Secrets Manager, S3, ECR
* Check security groups allow outbound HTTPS
## Instance type not available
**Symptoms:** Error like "m6i.xlarge is not available in us-east-1e"
**Fix:**
* Use multiple AZs (avoid `us-east-1d` and `us-east-1e` exclusively)
* Try a different region or instance type
* [Update stack parameters](/docs/ona/runners/aws/update-runner#update-parameters) or [create new environment class](/docs/ona/runners/aws/environment-classes)
* Retry later (availability is transient)
## Unexpected costs
**Symptoms:** Unexpected AWS charges, or continued billing after deleting a runner.
**Fix:**
* See [managing costs](/docs/ona/runners/aws/aws-runner-costs#controls-for-managing-costs) to identify resources
* After [deleting a runner](/docs/ona/runners/aws/delete-runner), verify the CloudFormation stack is fully deleted
* Check for residual EC2 instances or EBS volumes and delete manually
## SSM access blocked
**Symptoms:**
* Environments fail with `AWS account policy blocks ssm:SendCommand`
* Runner marked as degraded
* Slow startup (cache credentials can't refresh)
**Cause:** Service Control Policies (SCPs) blocking SSM access. The runner needs `ssm:SendCommand` and `ssm:GetCommandInvocation` permissions.
**Fix:** Request your AWS administrator add an exception for the runner's IAM role:
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["ssm:SendCommand", "ssm:GetCommandInvocation"],
"Resource": ["arn:aws:ec2:*:*:instance/*", "arn:aws:ssm:*:*:command/*"]
}]
}
```
## Prebuilds fail due to policy restrictions
**Symptoms:**
* Prebuilds fail with `AWS Service Control Policy blocks ec2:CreateSnapshot`
* Prebuilds fail with `AWS IAM policy does not allow ec2:CreateSnapshot`
* Similar errors for `ec2:RegisterImage`, `ec2:DescribeSnapshots`, or `ec2:DescribeImages`
**Cause:** Prebuilds require creating EBS snapshots and AMIs. These operations can be blocked by:
1. **Service Control Policies (SCPs)** - Organization-level policies that deny EC2 snapshot/AMI actions
2. **IAM policies** - The runner's IAM role is missing required permissions (outdated CloudFormation stack)
### Fix for SCP restrictions
Request your AWS administrator to allow these actions for the runner's IAM role in the SCP:
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"ec2:CreateSnapshot",
"ec2:RegisterImage",
"ec2:DescribeSnapshots",
"ec2:DescribeImages",
"ec2:DeleteSnapshot",
"ec2:DeregisterImage"
],
"Resource": "*"
}]
}
```
### Fix for IAM policy restrictions
[Update your CloudFormation stack](/docs/ona/runners/aws/update-runner) to the latest version. The latest stack template includes all required IAM permissions for prebuilds.
## Custom CA certificate issues
The `ca-trust-init` container in the Runner's ECS task logs can help diagnose CA issues. Check its **Status** (it should show `STOPPED` with exit code 0) and its **Logs** for errors and warnings.
### Environment stops shortly after starting
**Symptoms:** Environment starts but stops within seconds. No error is visible in the Ona dashboard.
**Cause:** The environment instance failed to download or parse the CA bundle. The instance shuts down when this fails.
**Fix:**
* Verify the CA bundle source (S3 bucket or HTTPS URL) is accessible from the runner's VPC
* For S3 URLs, ensure the bucket name starts with `gitpod-` — the runner's IAM role only has access to buckets matching `gitpod-*`
* Confirm the S3 object exists and the path in the `CustomCATrustBundle` parameter is correct
* Verify the CA bundle is valid PEM — the `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----` delimiters must each be on their own line
* Verify the CA bundle does not contain invalid content, such as displaying metadata before `-----BEGIN CERTIFICATE-----`
### User data is limited to 16384 bytes
**Symptoms:** Environment creation fails with `"User data is limited to 16384 bytes"`
**Cause:** The `CustomCATrustBundle` CloudFormation parameter uses an SSM dynamic reference (`{{resolve:ssm:...}}`), which embeds the full PEM certificate content into EC2 user data. CA bundles with multiple certificates exceed the 16 KB AWS limit.
**Fix:** Switch to an S3 URL for the trust bundle:
1. Create an S3 bucket with a name starting with `gitpod-` (e.g. `gitpod-myorg`)
2. Upload your CA bundle to `s3://gitpod-myorg/shared/ca-bundle.pem`
3. Update the `CustomCATrustBundle` CloudFormation parameter to `s3://gitpod-myorg/shared/ca-bundle.pem`
4. Update the CloudFormation stack
See [Custom CA Certificate](/docs/ona/runners/aws/setup#custom-ca-certificate) for details on all supported formats.
### CA not trusted in devcontainer builds
**Symptoms:** Devcontainer image builds or feature installs fail with TLS certificate errors, even though the custom CA works for other operations.
**Cause:** Custom CA certificates are applied to the runner and environment host but not injected into devcontainer build phases. Docker builds run in an isolated context that does not inherit the host's CA trust store.
**Fix:** Add your CA certificates directly to your devcontainer image:
```dockerfile theme={null}
COPY my-ca-bundle.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates
```
## Network connectivity issues
**Checklist:**
* Security groups: port 29222 (SSH), outbound HTTPS, port 22999 (internal)
* Route tables: public subnets → IGW, private subnets → NAT
* Network ACLs: not blocking required traffic
* DNS: VPC DNS resolution enabled, can resolve `app.gitpod.io`
**Test connectivity:**
```bash theme={null}
# Health endpoint (should return 200)
curl -v https:///_health
# Required endpoints
curl -I https://app.gitpod.io
curl -I https://public.ecr.aws
```
### Restart runner after network changes
After changing security groups, route tables, or VPC endpoints, restart the runner:
**Console:** ECS console → Clusters → your cluster → Services → Update → check **Force new deployment**
**CLI:**
```bash theme={null}
aws ecs update-service --cluster YOUR_CLUSTER_NAME --service YOUR_SERVICE_NAME --force-new-deployment
```
**Verify:** Check runner shows "Connected" in **Settings → Runners**, then test creating an environment.
## Getting help
Use **Support** from the organization menu. Include:
* Runner ID and version (from **Settings → Runners** → `...` menu)
* CloudFormation stack name and region
* Runner logs from CloudWatch (ECS task logs)
# Zscaler troubleshooting
Source: https://ona.com/docs/ona/runners/aws/troubleshooting-zscaler
Troubleshoot Zscaler compatibility issues with Ona
## HTTP/2 protocol downgrade
**Symptoms:** CLI failures, connection timeouts, protocol errors
**Cause:** Zscaler downgrades HTTP/2 to HTTP/1.1 for SSL-inspected traffic.
**Fix:** Contact your Zscaler admin to enable HTTP/2 for SSL-inspected traffic under `Administration > Advanced Settings`. See [Zscaler docs](https://www.zscaler.com/de/blogs/product-insights/http-2-better-faster-stronger).
If your organization uses a [custom domain](/docs/ona/custom-domain), make sure Zscaler preserves HTTP/2 for traffic to the custom management-plane hostname.
## SSL certificate verification failures
**Symptoms:** VS Code can't connect, "certificate verify failed", untrusted certificate warnings
**Cause:** Zscaler intercepts HTTPS and presents its own certificates. Apps with custom cert stores may not trust them.
**Check if Zscaler is intercepting:**
If your organization uses a [custom domain](/docs/ona/custom-domain), run this check against the custom management-plane hostname. Also check `app.gitpod.io` if users authenticate built-in integrations.
```bash theme={null}
curl -I -v https://app.gitpod.io
# Windows: curl.exe -I -v -w '\n%{certs}\n' https://app.gitpod.io
```
If the issuer shows "Zscaler Inc." instead of the expected certificate issuer, SSL inspection is active.
**Fix (recommended):** Add `app.gitpod.io` to SSL inspection bypass list.
If your organization uses a [custom domain](/docs/ona/custom-domain), add the custom management-plane hostname to the SSL inspection bypass list. Browser clients still need access to `app.gitpod.io` to authenticate built-in integrations.
**Alternative for VS Code:** Enable "System certificates" in VS Code settings (requires v1.97+). If issues persist, also enable "Electron Fetch" and "System Certificates V2".
## Runner connection issues
**Symptoms:** Runner can't connect, OAuth failures, "connection refused" errors
**Cause:** Zscaler is blocking the Ona management-plane hostname, OAuth callbacks, or runner-gateway protocols.
**Fix:**
* Allow outbound HTTPS (TCP 443) to the runner's configured Ona management-plane hostname (`app.gitpod.io` by default). Allowlist the hostname rather than the IP addresses it currently resolves to.
* Ensure WebSocket and gRPC traffic is allowed
* **Workaround:** Use Personal Access Tokens instead of OAuth while configuring
If your organization uses a [custom domain](/docs/ona/custom-domain), allow outbound HTTPS to the custom management-plane hostname used by the runner, not only `app.gitpod.io`.
## Configuration checklist
Work with your network team to configure:
**SSL inspection:**
* [ ] Add `app.gitpod.io` to the bypass list
* [ ] Verify the certificate shows the expected issuer, not "Zscaler"
If your organization uses a [custom domain](/docs/ona/custom-domain), also add the custom management-plane hostname to the bypass list and verify its certificate issuer.
**HTTP/2:**
* [ ] Enable HTTP/2 for SSL-inspected traffic in Advanced Settings
If your organization uses a [custom domain](/docs/ona/custom-domain), confirm this setting applies to traffic for the custom management-plane hostname.
**Network:**
* [ ] Allow outbound HTTPS (TCP 443) to `app.gitpod.io`
* [ ] Allow WebSocket and gRPC traffic
If your organization uses a [custom domain](/docs/ona/custom-domain), also allow outbound HTTPS, WebSocket, and gRPC traffic to the custom management-plane hostname.
## Verify configuration
If your organization uses a [custom domain](/docs/ona/custom-domain), replace `app.gitpod.io` with the custom management-plane hostname in both commands. Test `app.gitpod.io` separately if users authenticate built-in integrations.
```bash theme={null}
# Check SSL (issuer should not be Zscaler)
curl -I -v https://app.gitpod.io
# Check HTTP/2
curl --http2 -I https://app.gitpod.io
```
Then test VS Code extension and runner connectivity.
## Getting help
Collect and share with support:
* Output of `ona network-troubleshoot`, run from the machine where the connection to Ona is failing. This tests DNS, TCP, TLS, and authenticated API connectivity. See the [CLI reference](/docs/ona/reference/cli) for details.
* Output from `curl -I -v https://app.gitpod.io`
* [Runner support bundle](/docs/ona/troubleshooting#runner-support-bundles)
* [Environment support bundle](/docs/ona/troubleshooting#environment-support-bundles), if the environment is reachable
* VS Code / Ona extension logs
* Network configuration details
If your organization uses a [custom domain](/docs/ona/custom-domain), include the `curl -I -v` output for the custom management-plane hostname. Include the output for `app.gitpod.io` too if built-in integration authentication is affected.
# Upgrade runner
Source: https://ona.com/docs/ona/runners/aws/update-runner
CloudFormation infrastructure upgrades for AWS runners.
The AWS runner updates itself automatically for application-level changes. Update activity is logged to CloudWatch. For details on how automatic updates work and how to configure update windows, see [Automated updates](/docs/ona/runners/runner-updates).
This page covers AWS-specific update procedures: CloudFormation infrastructure upgrades and parameter changes.
## Upgrade runner infrastructure
When a new CloudFormation template version is available, you can upgrade your runner infrastructure directly from the Ona dashboard.
1. Navigate to **Settings → Runners** and select your runner
2. Open the runner menu (three-dot icon) and click **Upgrade runner**
3. Follow the instructions in the upgrade dialog. It provides the template URL for your runner
4. Open your runner's CloudFormation stack in the AWS console
5. Click **Update** → **Replace existing template** and enter the template URL from the dialog
6. Review parameters and complete the wizard
If your runner uses an Internet Gateway directly (without NAT or private network connectivity such as VPC endpoints), set the **Assign Public IP** parameter under [Network Configuration](/docs/ona/runners/aws/setup#network-configuration) to `true`.
Templates from January 2025 or earlier have SSH port changes. Before upgrading, stop and discard existing environments, or add port 22 to your security group.
## Update parameters
To change VPC, subnets, or other settings without updating the template:
1. Open your runner's CloudFormation stack
2. Click **Update** → **Use existing template**
3. Adjust parameters and complete the wizard
### Expanding availability zones
Availability is determined by your subnets, not the AZ parameter. Use the **VPC Resource Map** in AWS console to find subnets for your desired AZs.
# Configuring repository access
Source: https://ona.com/docs/ona/runners/configuring-repository-access
Configure repository access so environments on the runner can clone repositories from GitHub, GitLab, Bitbucket, or Azure DevOps. Do this during runner setup if users need to open repositories on that runner.
Skip this only if the runner will be used for empty environments with no repository clone step.
## Choose an authentication model
Each source control provider can expose one or more authentication methods:
* **OAuth** - users sign in through the source control provider
* **Personal access token** - users provide their own token
Choose the method that fits your operating model:
* use **OAuth** when you want a smoother user sign-in flow
* use **PATs** when your provider setup or internal policy favors user-managed tokens
* enable both if you want flexibility during rollout
## Add a provider
In the runner settings, click **Add a provider** and select the source control provider.
Configure the host for that provider. Use the default for public SaaS hosts such as `github.com`, or enter your self-hosted source control hostname.
If you need to support multiple hosts, add one provider entry per host.
Then configure at least one authentication method and save.
## Validate the setup
After saving:
1. open a repository on that host
2. start an environment on the runner
3. complete the user authentication flow if prompted
If the setup is correct, the environment should clone the repository successfully and proceed to provisioning.
## How authentication behaves
Users authenticate per source control host. Ona stores the resulting credentials in encrypted form so users do not need to repeat the same sign-in flow every time they start an environment.
If an admin disables an authentication method or deletes a provider integration, affected stored credentials are removed and users must authenticate again.
## Related pages
* [AWS runner overview](/docs/ona/runners/aws/overview)
* [AWS runner setup](/docs/ona/runners/aws/setup)
* [GCP runners](/docs/ona/runners/gcp/overview)
* [GCP runner setup](/docs/ona/runners/gcp/setup)
* [Source Control overview](/docs/ona/source-control/overview)
## Troubleshooting
* confirm the provider host matches the actual repository host
* confirm the user completed authentication for that host
* confirm the repository exists on a supported provider for the configured runner
* confirm the provider configuration was saved successfully
* confirm the authentication method they used is still enabled
* if the integration changed, expect users to authenticate again
This page still matters for public repositories, because the runner needs a configured provider to know how to access that host.
# Dev container image cache
Source: https://ona.com/docs/ona/runners/devcontainer-image-cache
Cache built Dev Container images to reduce environment startup times.
Requires [Core plan](https://ona.com/pricing) or higher.
The Dev Container image cache stores built Dev Container images in the runner's container registry. Environments with identical Dev Container configurations can reuse a cached image instead of rebuilding it from scratch, reducing startup time from minutes to seconds.
[Ona Cloud](/docs/ona/runners/ona-cloud) includes image caching by default. For runners in your own cloud account, Ona stores cached images in the runner's native registry: Amazon ECR for AWS runners and Google Artifact Registry for GCP runners.
## How it works
1. **Hash computation**: When starting an environment, Ona computes a hash from the Dev Container configuration, including:
* Contents of `devcontainer.json`
* Contents of any referenced `Dockerfile`
* Digest of any existing container image referenced directly in `devcontainer.json`
2. **Cache lookup**: Ona checks whether an image with this hash already exists:
* If found, Ona pulls and uses the cached image
* If not found, Ona builds a new image, pushes it to the cache, then uses it
3. **Shared caching**: The cache is shared across all users within a project. The first team member who starts an environment with a new Dev Container configuration builds and caches the image. Later environments in the same project with the same configuration use the shared cached image.
When rebuilding an existing environment's Dev Container, Ona tries to pull from the cache but does not push new cached images. Only the initial Dev Container build when an environment is created can push to the cache.
Non-project environments, such as environments started directly from a context URL, do not use the cache.
## Enable or disable the cache
For supported runners, configure the cache in runner settings:
1. Go to **Settings -> Runners** in your Ona organization
2. Select your runner
3. Toggle **Dev container image cache**
4. Click **Save**
Disabling the cache prevents new images from being cached and stops existing environments from pulling from the cache on rebuild. Existing cached images remain in the provider registry until they expire after 30 days or are manually deleted.
## What gets cached
The cache includes the built image from a `devcontainer build` of your configuration:
* **Base image layers**: Your specified base image and any modifications
* **Dev container features**: Configured Dev Container features
* **Build steps**: `RUN`, `COPY`, and other Dockerfile instructions
* **Tool installations**: Package managers, development tools, and dependencies installed during the build
The cache does not include:
* Lifecycle hooks such as `onCreateCommand`, which run after the environment starts
* User-specific configuration applied at runtime
* Files that change after container creation
## Cache invalidation
A new image is built and cached when:
* The Dev Container configuration hash changes
* `devcontainer.json` changes
* A referenced `Dockerfile` changes
* The digest of an image referenced directly in `devcontainer.json` changes
* The cached image expires
* The cached image is manually deleted from the provider registry
When `devcontainer.json` directly references an existing image, Ona includes the image digest in the cache key:
```json theme={null}
{
"image": "mcr.microsoft.com/devcontainers/typescript-node:0-18"
}
```
If the image maintainer publishes a new digest for the referenced tag, Ona invalidates the cache and builds a new cached image.
When `devcontainer.json` builds from a Dockerfile, Ona tracks the Dockerfile contents. Base images referenced in `FROM` instructions are not monitored directly, so change the Dockerfile or delete the cached image when you need to force a rebuild for base image updates.
## Force a new image build
To force rebuilding and re-caching an image, change the configuration hash or delete the cached image from the provider registry.
### Modify Dev Container configuration
Add or modify content in `devcontainer.json`:
```json theme={null}
{
"name": "My Dev Container",
"image": "mcr.microsoft.com/devcontainers/typescript-node:0-18",
"features": {
"ghcr.io/devcontainers/features/git:1": {}
}
}
```
### Modify the Dockerfile
If your Dev Container builds from a Dockerfile, change the Dockerfile:
```dockerfile theme={null}
FROM node:18
# Force rebuild: 2026-06-01
RUN npm install -g typescript
```
### Delete the provider registry image
Delete the cached image tag from the [AWS ECR](#aws-runners) or [Google Artifact Registry](#gcp-runners) repository for the project. The next environment creation rebuilds and caches the image.
## Supported configurations
Supported:
* Standard Dev Container configurations with a Dockerfile or direct image reference
* Dev Container features from any registry
* Ona Cloud
* AWS runners
* GCP runners
Not supported:
* Docker Compose-based Dev Containers
* Non-project environments, such as environments started directly from a context URL
## Monitoring
Cache hits are logged during environment creation:
```text theme={null}
Using pre-built dev container (saved ~3m45s build time)
```
## Security model
The Dev Container image cache is project-scoped:
* **Project isolation**: Cached images are only available to environments in the same project
* **Hash-based reuse**: Images are reused only for matching Dev Container configurations
* **Limited push access**: Push credentials are granted only during the initial environment build
* **Pull-only refreshes**: Existing environments receive refreshed pull credentials, not push credentials
* **Temporary credentials**: Registry credentials are short-lived and scoped to the project cache repository
Because cached images are shared across project members, do not write user-specific credentials or personal secrets into image layers. Use [organization secrets](/docs/ona/organizations/organization-secrets) or [project secrets](/docs/ona/projects/project-secrets) with build-time secret mounts when the build needs credentials.
## Provider details
### Ona Cloud
Ona Cloud includes Dev Container image caching by default. Ona manages the backing registry, lifecycle policy, and credentials.
### AWS runners
AWS runners store cached images in Amazon ECR in your AWS account. Cached image repositories use this naming pattern:
```text theme={null}
gitpod-runner-{runnerID}/projects/{projectID}/image-build
```
For existing AWS runners, upgrade the CloudFormation stack before enabling the cache:
1. [Upgrade your CloudFormation stack](/docs/ona/runners/aws/update-runner#upgrade-runner-infrastructure) to a version that supports the cache
2. Go to **Settings -> Runners** in your Ona organization
3. Select your AWS runner
4. Toggle **Dev container image cache**
5. Click **Save**
Upgrading CloudFormation templates that were applied from January 2025 or earlier will cause existing environments to no longer be accessible due to SSH port changes. Before upgrading, either stop and discard existing environments, or manually update the security group to allow access from `0.0.0.0/0` to port 22, in addition to port 29222, after upgrading the stack.
AWS storage and access details:
* Images are stored in Amazon ECR in the same AWS region as the runner
* ECR repositories inherit tags from the CloudFormation stack for cost allocation
* Repository tags are immutable
* Images expire after 30 days
* Registry access uses AWS IAM temporary credentials
To force a rebuild by deleting the cached image, delete the image tag from the runner's ECR repository. The next environment creation with the same Dev Container configuration rebuilds and caches the image.
### GCP runners
GCP runners store cached images in Google Artifact Registry in your Google Cloud project. Cached image repositories use this naming pattern:
```text theme={null}
{region}-docker.pkg.dev/{gcpProjectID}/gitpod-cache-{runnerID}/projects/{projectID}/image-build
```
The GCP runner Terraform module grants the required Artifact Registry permissions. When cache credentials are built, the runner creates or validates the `gitpod-cache-{runnerID}` repository in Artifact Registry. The same **Dev container image cache** runner setting controls whether project environments receive cache registry credentials.
GCP storage and access details:
* Images are stored in Artifact Registry
* The Artifact Registry repository uses Docker format
* Repository tags are immutable
* Images expire after 30 days
* Registry access uses temporary Google Cloud access tokens
To force a rebuild by deleting the cached image, delete the image tag from the runner's Artifact Registry repository. The next environment creation with the same Dev Container configuration rebuilds and caches the image.
## Troubleshooting
If images are not being cached:
1. **Check runner configuration**: Ensure the Dev Container image cache is enabled in runner settings
2. **Check the environment type**: Non-project environments do not use the cache
3. **Check provider infrastructure**: For AWS, verify the CloudFormation stack version and ECR permissions. For GCP, verify Terraform-managed Artifact Registry permissions
4. **Check runner logs**: Look for cache-related errors in CloudWatch for AWS runners or Cloud Logging for GCP runners
5. **Review environment logs**: Look for cache-related error messages
6. **Check image digest warnings**: If using the `image` field, look for digest lookup warnings that might indicate network or authentication issues with base image registries
If environments are still slow to start:
1. **Check cache hit logs**: Look for "Using pre-built dev container" in environment logs
2. **Check image size**: Large images take longer to pull
3. **Check Dev Container mode**: Docker Compose-based Dev Containers are not supported by the cache
4. **Review lifecycle hooks**: Lifecycle hooks such as `onCreateCommand` are not cached and may install tools that increase startup time. Move stable setup steps into the Docker build where possible
5. **Verify project-based environment**: Non-project environments do not use the cache
# Dual disk environments
Source: https://ona.com/docs/ona/runners/dual-disk
Use separate system and data disks for Enterprise environments on supported runners.
Available on the Enterprise plan for supported runners. [Contact sales](https://ona.com/contact/sales) to learn more.
Dual disk environments separate the VM system disk from the environment data disk. The system disk contains the operating system and runner-managed boot files. The data disk contains the workspace and development state that should survive VM replacement.
Dual disk gives Enterprise environments a more resilient storage model for long-running development work, larger repositories, prebuilds, and agent workloads.
## What dual disk preserves
The data disk stores development state across stops and starts:
* Repository contents and uncommitted changes under `/workspaces`
* Docker and containerd image layers used by Dev Containers
* Dev Container build output stored by the container runtime
* Runner-installed environment assets used during startup
When an environment stops, Ona can keep the data disk available for a fast restart. If the VM is later replaced, Ona can reattach the preserved disk or recreate it from a provider snapshot, depending on the runner and lifecycle state.
## How it changes environment restarts
With a single disk, the VM and the environment's data are tied to the same root disk lifecycle. With dual disk, the VM can be treated as replaceable compute while the environment data remains on a separate provider-managed disk.
| Environment state | What happens with dual disk |
| ----------------- | ----------------------------------------------------------------------------------------------- |
| Running | The VM uses a system disk plus a separate data disk. |
| Stopped briefly | The same VM or attached data disk can be reused for a faster restart. |
| Stopped longer | The data disk can be detached and later restored from a snapshot. |
| Deleted | Environment data is permanently removed according to the normal environment deletion lifecycle. |
Dual disk does not change how developers use environments. Files remain available at the usual paths, including `/workspaces`.
## Prebuilds, base snapshots, and warm pools
Dual disk works with [prebuilds](/docs/ona/projects/prebuilds) and [warm pools](/docs/ona/projects/warm-pools).
For eligible Enterprise AWS runners, Ona automatically maintains [base snapshots](/docs/ona/runners/aws/base-snapshots) of the organization default image and shared startup assets. A new environment can restore this cached data onto its data disk instead of pulling it during every cold start. Base snapshots contain no project workspace or user state and remain scoped to one organization and runner.
For dual disk prebuilds, the prebuild output is captured as a data disk snapshot. New environments then start from the runner's normal system image plus a data disk created from that snapshot. This keeps prebuilt workspace state, dependencies, and container layers on the data disk while letting the runner use the current system image for the VM.
For warm pools, each warm pool instance receives its own data disk from the prebuild snapshot. When a warm pool instance is claimed as a real environment, that data disk becomes the environment's persistent data source.
## Runner support
Dual disk is available for Enterprise customers on supported AWS and GCP runners. Existing runners may need to be upgraded before they can create dual disk environments.
* For AWS runners, use the latest AWS runner infrastructure and runner version. See [Upgrade runner](/docs/ona/runners/aws/update-runner).
* For GCP runners, use the latest Terraform module and runner version. See [Upgrade and delete runner](/docs/ona/runners/gcp/update-runner).
GCP runners can also enable cross-zone restart for stopped dual disk environments. This allows a stopped environment to restart in another zone when the original zone has no VM capacity. See the [GCP setup guide](/docs/ona/runners/gcp/setup#cross-zone-restart).
## Relationship to persistent storage
Dual disk is an infrastructure-level improvement to [persistent storage](/docs/ona/environments/persistent-storage). It does not require developers to change where they store files, and it does not replace project-level features such as [Dev Container image caching](/docs/ona/runners/devcontainer-image-cache), [prebuilds](/docs/ona/projects/prebuilds), or [warm pools](/docs/ona/projects/warm-pools).
Use those features together:
* Use persistent storage for developer state across stops and starts.
* Use dual disk for more resilient runner-managed storage.
* Let Ona maintain base snapshots to cache organization-wide default-image data on eligible AWS runners.
* Use prebuilds and warm pools to reduce startup time.
* Use Dev Container image caching to avoid repeated image builds for the same configuration.
## FAQ
No. Dual disk keeps the same in-environment paths, including `/workspaces`, so existing Dev Container configurations continue to work.
Not necessarily. Dual disk preserves environment data, not the identity of the VM. If Ona restarts the same stopped VM, the private IP can remain the same. If Ona replaces the VM and reattaches or restores the data disk, the VM may receive a new private IP.
No. Deleting an environment still permanently removes its environment data according to the normal deletion lifecycle.
# Alerts and Dashboards
Source: https://ona.com/docs/ona/runners/gcp/alerts-and-dashboards
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Ona provides pre-built Grafana alerts and a dashboard for GCP Runners. These live in the [`terraform-google-ona-runner`](https://github.com/gitpod-io/terraform-google-ona-runner) repository under the [`monitoring/`](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring) directory and are designed to work with the Prometheus metrics your runner already exposes.
Before using these alerts and dashboards, you need to configure metrics collection on your runner. See [Custom metrics pipeline](/docs/ona/runners/monitoring-and-metrics) for setup instructions.
## Prerequisites
* A deployed GCP Runner with [metrics collection enabled](/docs/ona/runners/monitoring-and-metrics)
* A Grafana instance (or compatible alerting system) connected to your Prometheus data source
## Dashboard
The repository includes a Grafana dashboard at [`monitoring/dashboards/gitpod-runner-overview.json`](https://github.com/gitpod-io/terraform-google-ona-runner/blob/main/monitoring/dashboards/gitpod-runner-overview.json).
### What it covers
| Section | What it shows |
| ---------------------------- | ----------------------------------------------------------------- |
| **Version & Replicas** | Runner version tracking and replica count |
| **Health Status** | Health checks and active instance states by lifecycle stage |
| **GCP Runner Kit Interface** | Environment operation durations, function calls, error rates |
| **GCP API Operations** | API request metrics, success rates, error rates, latency heatmaps |
| **KV Store Operations** | Redis/key-value store operation rates and durations |
| **PubSub Operations** | Message processing, acknowledgments, connection health |
| **Environment Operations** | Compute environment operation rates and durations |
| **System Metrics** | Host-level CPU, memory, disk usage, and disk I/O |
| **WRI** | Workspace Runtime Interface performance metrics |
The dashboard uses template variables (`$project_id`, `$region`, `$runner_name`, `$instance`) so you can filter by deployment.
### Import the dashboard
1. In Grafana, go to **Dashboards → Import**
2. Upload `gitpod-runner-overview.json` from the repository
3. Select your Prometheus data source
4. Configure the template variables to match your deployment
## Alerts
The repository includes 19 alert definitions at [`monitoring/alerts/`](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts), each in its own folder with an `alert.yaml` (Grafana-compatible alert rule) and a `runbook.md` (troubleshooting steps).
### Alert overview
#### Critical — immediate response required
These indicate a service outage or severe degradation.
| Alert | Condition | Impact |
| ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------------ |
| [Service Down](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/service-down) | Runner or auth proxy `up` metric is 0 for >1 min | Complete outage — users cannot create or manage environments |
| [High Error Rate](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/high-error-rate) | >10% of environment operations failing over 5 min | Users experiencing environment creation failures |
| [High Latency](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/high-latency) | 95th percentile operation time >5 min | Slow environment operations |
| [Goroutine Panics](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/goroutine-panics) | Application panics detected | Potential service instability |
#### High — prompt attention required
These indicate degraded performance or functionality.
| Alert | Condition |
| ----------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| [API Rate Limiting](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/api-rate-limiting) | Hitting GCP API rate limits |
| [PubSub Backlog](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/pubsub-backlog) | >1000 unprocessed messages |
| [PubSub Connection Health](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/pubsub-connection-health) | PubSub connectivity issues |
| [Circuit Breaker Open](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/circuit-breaker-open) | Circuit breaker protecting system from cascading failures |
| [Redis Connection Issues](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/redis-connection-issues) | Redis connectivity problems |
#### Medium — monitor and track
These indicate reduced capacity or resource constraints.
| Alert | Condition |
| ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| [High CPU Usage](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/high-cpu-usage) | CPU usage >80% for extended period |
| [High Memory Usage](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/high-memory-usage) | Memory usage >80% for extended period |
| [High Disk Usage](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/high-disk-usage) | Disk usage >85% for extended period |
| [Network Connection Health](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/network-connection-health) | Network connectivity issues |
| [Network Errors](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/network-errors) | High rate of network errors |
| [Registry Health](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/registry-health) | Container registry connectivity issues |
| [Zone Capacity Issues](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/zone-capacity-issues) | GCP zone unavailable or at capacity |
| [Quota Exceeded](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/quota-exceeded) | GCP resource quotas hit limits |
#### Info — optimization opportunities
| Alert | Condition |
| ------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
| [High Process Memory Usage](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/high-process-memory-usage) | Process memory usage >1GB for extended period |
| [High Goroutine Count](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring/alerts/high-goroutine-count) | >1000 active goroutines |
### Import alerts into Grafana
Each alert folder contains an `alert.yaml` file:
1. In Grafana, go to **Alerting → Alert Rules**
2. Click **Import**
3. Upload the `alert.yaml` from the alert folder you want (e.g., `service-down/alert.yaml`)
4. Configure notification channels for the alert's severity level
### Customize thresholds
The default thresholds work for most deployments. Adjust them based on your scale:
* **Smaller deployments** may need lower thresholds to catch issues earlier
* **Larger deployments** may need higher thresholds to reduce noise
* **Development environments** may want less sensitive alerts
### Runbooks
Each alert folder also contains a `runbook.md` with step-by-step troubleshooting instructions. Before using a runbook, set up these environment variables:
```bash theme={null}
export PROJECT_ID="your-gcp-project-id"
export REGION="your-region" # e.g., us-central1
export RUNNER_ID="your-runner-id" # from your Terraform configuration
```
The runbooks use `gcloud compute ssh` commands to inspect the runner instance and include resolution steps and escalation procedures.
## Notification channels
Configure notification channels in Grafana based on alert severity:
| Severity | Suggested channels |
| -------- | ----------------------- |
| Critical | PagerDuty, SMS, phone |
| High | Slack, email |
| Medium | Email, ticket creation |
| Info | Email, dashboard review |
## Next steps
* [Custom metrics pipeline](/docs/ona/runners/monitoring-and-metrics) — Enable metrics collection and see all available metrics
* [Troubleshooting GCP Runners](/docs/ona/runners/gcp/troubleshooting-runners) — Diagnose common runner issues
* [`monitoring/` on GitHub](https://github.com/gitpod-io/terraform-google-ona-runner/tree/main/monitoring) — Browse alert definitions and dashboard source
# GCP access requirements
Source: https://ona.com/docs/ona/runners/gcp/detailed-access-requirements
Configure your firewall rules, IAM permissions, and network security to allow the required connections for your GCP Runner to function properly.
## IAM Permissions Required
Your GCP service account needs the following permissions to deploy and manage the runner infrastructure:
### Required Roles
* **Compute Admin** (`roles/compute.admin`) - Manage VMs, networks, and load balancers
* **Storage Admin** (`roles/storage.admin`) - Manage Cloud Storage buckets and objects
* **Artifact Registry Administrator** (`roles/artifactregistry.admin`) - Manage container images
* **Secret Manager Admin** (`roles/secretmanager.admin`) - Store and retrieve secrets
* **Service Account Admin** (`roles/iam.serviceAccountAdmin`) - Create service accounts for runner components
* **Project IAM Admin** (`roles/resourcemanager.projectIamAdmin`) - Manage project-level IAM bindings
### Custom Role (Alternative)
Instead of broad roles, you can create a custom role with specific permissions. GCP custom roles do not support wildcards, so you must list each permission explicitly. The example below covers the most common permissions needed:
```json theme={null}
{
"title": "Ona GCP Runner Role",
"description": "Permissions required for Ona GCP Runner deployment",
"stage": "GA",
"includedPermissions": [
"compute.instances.create",
"compute.instances.delete",
"compute.instances.get",
"compute.instances.list",
"compute.instances.setMetadata",
"compute.instances.setTags",
"compute.instances.start",
"compute.instances.stop",
"compute.instances.resume",
"compute.instanceGroups.create",
"compute.instanceGroups.delete",
"compute.instanceGroups.get",
"compute.instanceGroups.list",
"compute.instanceGroups.update",
"compute.networks.get",
"compute.networks.list",
"compute.subnetworks.get",
"compute.subnetworks.list",
"compute.subnetworks.use",
"compute.firewalls.create",
"compute.firewalls.delete",
"compute.firewalls.get",
"compute.firewalls.list",
"compute.firewalls.update",
"compute.forwardingRules.create",
"compute.forwardingRules.delete",
"compute.forwardingRules.get",
"compute.forwardingRules.list",
"compute.backendServices.create",
"compute.backendServices.delete",
"compute.backendServices.get",
"compute.backendServices.list",
"compute.backendServices.update",
"compute.healthChecks.create",
"compute.healthChecks.delete",
"compute.healthChecks.get",
"compute.healthChecks.list",
"compute.healthChecks.update",
"storage.buckets.create",
"storage.buckets.delete",
"storage.buckets.get",
"storage.buckets.list",
"storage.objects.create",
"storage.objects.delete",
"storage.objects.get",
"storage.objects.list",
"artifactregistry.repositories.create",
"artifactregistry.repositories.delete",
"artifactregistry.repositories.get",
"artifactregistry.repositories.list",
"secretmanager.secrets.create",
"secretmanager.secrets.delete",
"secretmanager.secrets.get",
"secretmanager.secrets.list",
"secretmanager.versions.add",
"secretmanager.versions.access",
"secretmanager.versions.get",
"secretmanager.versions.list",
"iam.serviceAccounts.create",
"iam.serviceAccounts.delete",
"iam.serviceAccounts.get",
"iam.serviceAccounts.list",
"resourcemanager.projects.setIamPolicy",
"resourcemanager.projects.getIamPolicy"
]
}
```
This list covers the most common deployment permissions. Depending on your configuration (CMEK, internal LB, etc.), additional permissions may be required. Refer to the [IAM configuration guide](https://github.com/gitpod-io/terraform-google-ona-runner/blob/main/docs/iam.md) in the Terraform module for the complete list.
## Network Connectivity Requirements
Configure your firewall and network security groups to allow outbound connections to these endpoints.
### Ona Services
#### Management Plane
Controls Runner and Environment orchestration by communicating with Ona's control plane.
* `https://app.gitpod.io`
* `https://app.ona.com`
### VS Code
Required for VS Code IDE functionality including server downloads and extension marketplace access.
* `https://update.code.visualstudio.com/api/commits/stable/server-linux-x64-web`
* `https://update.code.visualstudio.com/api/commits/stable/server-linux-arm64-web`
* `https://update.code.visualstudio.com/commit:*/server-linux-x64/stable`
* `https://update.code.visualstudio.com/commit:*/server-linux-arm64/stable`
* `https://*.vscode-unpkg.net`
* `https://marketplace.visualstudio.com`
* `https://*.gallerycdn.vsassets.io`
* `https://*.prss.microsoft.com`
* `https://*.vscode-gitpod-cdn.com` (required for VS Code Web functionality)
* `https://vscode.gitpod.io` (required for VS Code Web functionality)
### JetBrains
Required for JetBrains IDE functionality including IDE downloads and services.
* `https://www.jetbrains.com`
* `https://download.jetbrains.com`
* `https://download-cf.jetbrains.com`
* `https://download-cdn.jetbrains.com`
* `https://data.services.jetbrains.com`
* `https://plugins.jetbrains.com`
* `https://downloads.marketplace.jetbrains.com`
* `https://account.jetbrains.com`
See the [JetBrains network access requirements](/docs/ona/editors/jetbrains#network-access-requirements) for more details.
### Release Artifacts
Downloads Ona updates, CLI binaries, and agent components necessary for Runner and Environment operation. These are served from `app.gitpod.io/releases/*` (same domain as the control plane). This access is required from the user laptops.
* `https://app.gitpod.io/releases/cli/stable/manifest.json`
* `https://app.gitpod.io/releases/cli/stable/gitpod-linux-amd64`
* `https://app.gitpod.io/releases/cli/stable/gitpod-linux-amd64.exe`
* `https://app.gitpod.io/releases/cli/stable/gitpod-linux-amd64.sha256`
* `https://app.gitpod.io/releases/cli/stable/gitpod-linux-arm64`
* `https://app.gitpod.io/releases/cli/stable/gitpod-linux-arm64.sha256`
* `https://app.gitpod.io/releases/vscode/releases/*/vscode-remote.vsix`
* `https://app.gitpod.io/releases/vscode/releases/*/vscode-agent-amd64`
* `https://app.gitpod.io/releases/vscode/releases/*/vscode-agent-arm64`
* `https://app.gitpod.io/releases/jetbrains/releases/*/jetbrains-agent-amd64`
* `https://app.gitpod.io/releases/jetbrains/releases/*/jetbrains-agent-arm64`
### Container Registries
Downloads container images used by development environments and runner infrastructure.
**Ona runner images (Google Artifact Registry):**
* `https://us-docker.pkg.dev/gitpod-artifacts/docker-public` (project ID: `760152953637`)
**Ona default Dev Container image:**
* `https://mcr.microsoft.com/devcontainers/base:2.0.4-noble`
### Your Infrastructure
#### Runner Proxy Domain
The runner must be able to reach its own configured domain over HTTPS. It periodically verifies DNS resolution and TLS connectivity by requesting `https:///_health`. Blocking this egress causes the runner to report degraded status.
* `https://` (the domain you configured during setup)
#### SCM and SSO Providers
Access to your source code repositories and authentication providers for user login and code access.
Configure access to your specific providers (complete HTTPS URLs):
* GitHub, GitLab, Bitbucket URLs
* SSO provider URLs (Okta, Azure AD, etc.)
### Optional Services
#### Prometheus Remote Write
Optional metrics collection endpoint for monitoring Runner and Environment performance.
* Your metrics endpoint URL (HTTPS 443)
#### Additional Container Registries
Optional access to custom container registries for pulling private or organization-specific images.
**Common registries (allow those you use):**
* `https://index.docker.io`
* `https://registry-1.docker.io`
* `https://auth.docker.io`
* `https://ghcr.io`
* Your private registry URLs (HTTPS 443)
## GCP Services and APIs Required
### Core GCP Services
| Service | API Endpoint | Purpose | Why Needed |
| --------------------- | --------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **Compute Engine** | `compute.googleapis.com` | VM management and networking | Creates development environment VMs, manages instance groups, autoscaling, load balancers, and networking infrastructure |
| **Cloud Storage** | `storage.googleapis.com` | Object storage | Stores build cache, environment snapshots, and Terraform state with lifecycle management |
| **Artifact Registry** | `artifactregistry.googleapis.com` | Container registry | Stores and manages container images for development environments with vulnerability scanning |
| **Secret Manager** | `secretmanager.googleapis.com` | Secure credential storage | Stores runner authentication tokens, the runner secrets key, SSL certificates, and other sensitive configuration securely |
| **Cloud Logging** | `logging.googleapis.com` | Centralized logging | Collects logs from runner components and development environments for debugging and monitoring |
| **Cloud Monitoring** | `monitoring.googleapis.com` | Infrastructure monitoring | Monitors VM health, resource utilization, and provides alerting for runner infrastructure |
### Supporting GCP Services
| Service | API Endpoint | Purpose | Why Needed |
| ------------------------- | ------------------------------- | --------------------- | ---------------------------------------------------------------------------------- |
| **Memorystore for Redis** | `redis.googleapis.com` | In-memory data store | Stores runner state, session information, and coordinates between runner instances |
| **Cloud Run** | `run.googleapis.com` | Serverless containers | Provides serverless execution environment for auxiliary services and webhooks |
| **Cloud Pub/Sub** | `pubsub.googleapis.com` | Event processing | Processes compute lifecycle events for event-driven environment reconciliation |
| **Cloud Functions** | `cloudfunctions.googleapis.com` | Serverless functions | Handles authentication proxy and event-driven workflows |
### Required APIs
| API | Endpoint | Purpose | Why Needed |
| ---------------------------------- | ------------------------------------- | --------------------------- | --------------------------------------------------------------------------------------------- |
| **Identity and Access Management** | `iam.googleapis.com` | Access control | Creates service accounts, custom roles, and manages permissions for runner components |
| **IAM Credentials** | `iamcredentials.googleapis.com` | Token generation | Generates short-lived access tokens for secure service-to-service authentication |
| **Cloud Resource Manager** | `cloudresourcemanager.googleapis.com` | Project management | Manages project-level IAM policies and resource organization |
| **VPC Access** | `vpcaccess.googleapis.com` | Serverless VPC connectivity | Enables Cloud Run services to access VPC resources securely |
| **Service Networking** | `servicenetworking.googleapis.com` | Private connectivity | Creates private connections to managed services like Memorystore Redis |
| **Cloud KMS** | `cloudkms.googleapis.com` | (Optional) CMEK encryption | Encrypts persistent disks, storage buckets, and secrets with customer-managed encryption keys |
### Metadata Service Access
| Endpoint | Protocol | Purpose | Why Needed |
| ---------------------------------------------- | -------- | ------------------- | -------------------------------------------------------------------------------------------------- |
| `metadata.google.internal` (`169.254.169.254`) | HTTP | VM metadata service | Required for GCP VM instances to access metadata, service account tokens, and instance information |
## Image Access Requirements
GCP Runners require access to specific VM images. If your GCP Organization restricts image access through organizational policies, ensure your GCP project can launch Compute Engine instances from these images.
### Required Images
| Image Family | Project/Source | Owner | Purpose |
| ------------------- | ------------------------ | ------ | --------------------------- |
| `cos-stable` | `cos-cloud` | Google | Runner orchestrator service |
| `ona-environment-*` | `gitpod-next-production` | Ona | Development environment VMs |
### Organizational Policy Configuration
If your organization uses image access restrictions, configure your organizational policy to allow:
```yaml theme={null}
# Example organizational policy constraint
constraint: compute.trustedImageProjects
listPolicy:
allowedValues:
- "projects/cos-cloud"
- "projects/gitpod-next-production"
```
### Allowlisting Recommendations
**Use Project-Level Access**: Allow access by project ID rather than specific image names to automatically receive security updates and new features.
**Regular Updates**: Ona updates images regularly for security patches and feature improvements. Project-level access ensures automatic access to updated images.
**Testing Access**: Verify image access before deployment:
```bash theme={null}
# Test access to required images
gcloud compute images list --project=cos-cloud --filter="family:cos-stable"
gcloud compute images list --project=gitpod-next-production --filter="name:ona-environment-*"
```
## Quota Requirements
Ensure your GCP project has sufficient quotas for the runner deployment:
### Compute Engine Quotas
| Resource | Minimum Required | Recommended | Purpose |
| ---------------------------- | ---------------- | ----------- | --------------------------- |
| **CPUs** | 100 | 500+ | Development environment VMs |
| **Persistent Disk SSD (GB)** | 1,000 | 5,000+ | Environment storage |
| **In-use IP addresses** | 50 | 200+ | VM networking |
| **Firewall rules** | 10 | 50+ | Network security |
| **Forwarding rules** | 5 | 20+ | Load balancer configuration |
| **Backend services** | 5 | 20+ | Load balancer backends |
### Regional Quotas
Quotas are region-specific. Ensure adequate quotas in your deployment region:
```bash theme={null}
# Check current quotas
gcloud compute project-info describe --project=YOUR_PROJECT_ID
```
### Requesting Quota Increases
For production deployments, request quota increases through the GCP Console:
1. Navigate to **IAM & Admin** → **Quotas**
2. Filter by service: **Compute Engine API**
3. Select your deployment region
4. Request increases for the resources listed above
## Troubleshooting
**Insufficient IAM Permissions**: Verify your service account has the required roles listed above.
**API Not Enabled**: Enable all required APIs in your GCP project:
```bash theme={null}
# Enable required APIs
gcloud services enable compute.googleapis.com \
storage.googleapis.com \
artifactregistry.googleapis.com \
secretmanager.googleapis.com \
iam.googleapis.com \
cloudresourcemanager.googleapis.com \
networkconnectivity.googleapis.com \
redis.googleapis.com
```
**Image Access Denied**: Check organizational policies and image project access.
**Quota Exceeded**: Monitor quota usage and request increases before deployment.
Test your access before deployment:
```bash theme={null}
# Test compute permissions
gcloud compute instances list --project=YOUR_PROJECT_ID
# Test storage permissions
gcloud storage buckets list --project=YOUR_PROJECT_ID
# Test IAM permissions
gcloud iam service-accounts list --project=YOUR_PROJECT_ID
```
# Costs & Budgeting for GCP Runner
Source: https://ona.com/docs/ona/runners/gcp/gcp-runner-costs
This guide outlines the costs associated with the GCP runner infrastructure. It does not include development environment costs or license fees. For an overview of what a GCP runner is, see [GCP Runners](/docs/ona/runners/gcp/overview).
GCP costs mentioned in this document are subject to change and may vary by region. Check the latest pricing on the [GCP pricing pages](https://cloud.google.com/pricing).
## Billable GCP resources
The following are the billable resources deployed by the GCP runner:
* **Compute Engine Instances**: Managed instance groups for runner and proxy services
* **Memorystore Redis**: Used to store state related to environment reconciliation
* **Cloud Storage Buckets**: Used to store build cache, runner assets, and CA certificates
* **Load Balancer Components**: Health checks, backend services, and forwarding rules
* **Secret Manager**: Used to store runner credentials, the runner secrets key, and metrics configuration
* **Cloud Logging**: Used to store logs related to runner instances
* **VPC Networking**: Private service connections and IP address reservations
* **Cloud KMS** (optional): Customer-managed encryption keys for enhanced security
## Baseline costs of a runner
The primary costs associated with a GCP runner include:
### Core Infrastructure (Always-On)
* **Compute Engine Instances**:
* Runner instance: 1x `c4-standard-4` (4 vCPU, 16GB RAM) = \~\$120/month
* Proxy instances: 2x `c4-standard-2` (2 vCPU, 8GB RAM each) = \~\$120/month total
* **Subtotal: \~\$240/month**
* **Memorystore Redis**: Standard HA instance with 2GB memory = \~\$70/month
* **Load Balancer**: Global or regional load balancer = \~\$18-25/month
### Storage and Networking
* **Cloud Storage**: Build cache and assets storage (\~\$2-10/month depending on usage)
* **VPC Networking**: Private service connections and IP reservations (\~\$3-8/month)
* **Secret Manager**: Minimal cost for storing credentials (\~\$0.50-2/month)
* **Cloud Logging**: Log storage and ingestion (\~\$2-15/month depending on log volume)
### Optional Components
* **Cloud KMS**: Customer-managed encryption keys (\~\$1-3/month if enabled)
* **Certificate Manager**: SSL certificate management (free for Google-managed certificates)
**Total Estimated Monthly Cost**: \$340-380 for a typical deployment, not including development environment costs.
These are baseline estimates. Actual costs may vary based on region, usage patterns, and configuration choices.
## Controls for Managing Costs
### Viewing Runner Costs
To view isolated runner costs in **Google Cloud Console**:
1. **Navigate to Cloud Billing** → **Cost breakdown**.
2. **Group by Service** to analyze the breakdown of costs.
3. **Filter by labels** to isolate runner-specific resources:
* **Runner Name**: Use the `gitpod-runner` label with your runner name value.
* **Component**: Filter by `gitpod-component` label to see specific components (redis, build-cache, etc.).
* **Managed by Terraform**: Use the `managed-by` label with value `terraform`.
### Viewing Environment Costs
To view isolated environment costs in **Google Cloud Console**:
1. **Navigate to Cloud Billing** → **Cost breakdown**.
2. **Group by Service** to analyze the breakdown of costs.
3. **Filter by the environment ID** using labels:
* **Label**: `gitpod-environment-id`
* **Value**: The environment ID (you can find this by selecting **Copy ID** from the environment details)
### Using Cost Management Tools
#### Budget Alerts
Set up budget alerts to monitor runner costs:
1. **Navigate to Cloud Billing** → **Budgets & alerts**
2. **Create a new budget** with filters for your runner resources
3. **Set threshold alerts** at 50%, 80%, and 100% of your expected monthly cost
4. **Configure notifications** to email or Slack channels
#### Cost Anomaly Detection
Enable cost anomaly detection to catch unexpected cost spikes:
1. **Navigate to Cloud Billing** → **Cost insights**
2. **Enable anomaly detection** for your project
3. **Configure alerts** for cost anomalies above your threshold
## Compute Engine instance labeling
All Compute Engine instances launched by Ona GCP runners automatically inherit labels from the Terraform configuration. This means:
* Any labels you add to the Terraform variables will be propagated to the Compute Engine instances created for environments
* This allows for consistent resource labeling across your GCP infrastructure
* Labels can be used for cost allocation, resource grouping, and access control
### Adding Labels to Compute Engine Instances
To add labels to Compute Engine instances launched by Ona:
1. Update your `terraform.tfvars` file with additional labels:
```hcl theme={null}
labels = {
environment = "production"
team = "platform"
cost-center = "engineering"
project = "ona-runner"
}
```
2. Apply the Terraform changes:
```bash theme={null}
terraform plan
terraform apply
```
All new Compute Engine instances launched after the update will include these labels.
When you update Terraform labels, the changes don't immediately apply to existing instances. To force existing instances to pick up the new labels, you can trigger a rolling update of the managed instance groups:
```bash theme={null}
# Update runner instances
gcloud compute instance-groups managed rolling-action restart \
RUNNER_INSTANCE_GROUP_NAME --region=REGION
# Update proxy instances
gcloud compute instance-groups managed rolling-action restart \
PROXY_INSTANCE_GROUP_NAME --region=REGION
```
This will recreate instances with the updated labels without affecting running development environments.
## Cost optimization strategies
### Right-sizing Instances
Monitor instance utilization and adjust machine types:
1. **Review CPU and memory utilization** in Cloud Monitoring
2. **Consider smaller instance types** for low-utilization runners
3. **Use custom machine types** for optimal resource allocation
### Storage Optimization
Optimize storage costs for build cache and assets:
1. **Configure lifecycle policies** on Cloud Storage buckets to automatically delete old cache data
2. **Monitor storage usage** and adjust retention policies as needed
3. **Use regional storage** instead of multi-regional for cost savings
### Redis Optimization
Optimize Memorystore Redis costs:
1. **Monitor memory utilization** and adjust instance size accordingly
2. **Consider Basic tier** instead of Standard HA for non-production environments (saves \~\$35/month)
3. **Use smaller memory sizes** if your workload permits:
* 1GB instead of 2GB = \~\$15-20/month savings
* Monitor actual Redis memory usage in Cloud Monitoring
### Load Balancer Optimization
Optimize load balancer costs:
1. **Use internal load balancers** when external access isn't required
2. **Monitor data transfer costs** and optimize routing
3. **Consider regional load balancers** for single-region deployments
## Resource cleanup
### Automatic Cleanup
The GCP runner includes automatic cleanup mechanisms:
* **Build cache lifecycle**: Automatically deletes cache data older than 30 days
* **Log retention**: Cloud Logging automatically manages log retention based on your settings
* **Incomplete uploads**: Automatically aborts incomplete multipart uploads after 1 day
### Manual Cleanup
For cost optimization, consider manual cleanup of:
* **Unused persistent disks** from terminated environments
* **Old machine images** if using custom images
* **Unused static IP addresses** if any were manually created
### Deleting the runner
To completely remove runner infrastructure and stop all associated costs, follow [Delete runner](/docs/ona/runners/gcp/update-runner#delete-runner). That guide covers disconnecting the runner in Ona, running `terraform destroy`, and checking for leftover resources that can drive costs after deletion (persistent disks, snapshots, reserved IP addresses, storage buckets).
## Cost monitoring best practices
### Regular Cost Reviews
1. **Weekly cost reviews**: Monitor costs weekly to catch anomalies early
2. **Monthly budget analysis**: Compare actual vs. budgeted costs monthly
3. **Quarterly optimization**: Review and optimize resource allocation quarterly
### Cost Attribution
1. **Use consistent labeling**: Apply consistent labels across all resources
2. **Environment-specific tracking**: Track costs per development environment
3. **Team-based allocation**: Allocate costs to specific teams or projects
### Alerting and Notifications
1. **Set up budget alerts**: Configure alerts at multiple thresholds
2. **Monitor cost anomalies**: Enable automatic anomaly detection
3. **Regular reporting**: Set up automated cost reports for stakeholders
## Troubleshooting
1. **Runaway environments**: Environments that don't shut down properly
2. **Large build caches**: Excessive storage usage in build cache buckets
3. **High data transfer**: Unexpected network egress charges
4. **Oversized instances**: Using larger instance types than necessary
1. **Check Cloud Billing reports** for cost breakdown by service
2. **Review resource utilization** in Cloud Monitoring
3. **Audit running instances** and their utilization
4. **Check storage usage** in Cloud Storage buckets
5. **Review network traffic** patterns and data transfer costs
1. **Terminate unused environments** manually if auto-shutdown fails
2. **Clean up old build cache data** beyond the automatic lifecycle
3. **Optimize instance types** based on actual utilization
4. **Review and adjust** Redis instance sizing
5. **Optimize load balancer configuration** for your traffic patterns
# GCP runners
Source: https://ona.com/docs/ona/runners/gcp/overview
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
GCP Runners deploy Ona's runner infrastructure inside your own Google Cloud VPC. Development environments run as Compute Engine instances in your project. Source code and credentials never leave your infrastructure.
## Architecture
A GCP Runner consists of:
* **Runner orchestrator**: a containerized service running on Compute Engine that manages environment lifecycle
* **Environment VMs**: Compute Engine instances automatically sized based on your environment class configuration
* **Load balancer**: routes traffic to environments, available as [external or internal](/docs/ona/runners/gcp/reference-architectures)
* **Supporting services**: Memorystore Redis for state, Cloud Storage for build cache, Artifact Registry for container images
## Getting started
The runner is deployed using a [Terraform module](https://registry.terraform.io/modules/gitpod-io/ona-runner/google/latest) that provisions and configures all components. The [Setup guide](/docs/ona/runners/gcp/setup) walks you through the process step by step, from creating the runner in the Ona dashboard to verifying it's online.
Before deploying, you may want to review the [reference architectures](/docs/ona/runners/gcp/reference-architectures) to choose between external and internal load balancer modes based on your network requirements.
| | |
| -------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| [Setup](/docs/ona/runners/gcp/setup) | Step-by-step deployment with Terraform |
| [Reference architectures](/docs/ona/runners/gcp/reference-architectures) | External vs internal load balancer modes, networking, and certificate requirements |
| [Access requirements](/docs/ona/runners/gcp/detailed-access-requirements) | IAM permissions, network connectivity, GCP APIs, and image access |
| [Private GAR images](/docs/ona/runners/gcp/private-gar-images) | Use private Google Artifact Registry images in Dev Containers |
| [Costs & budgeting](/docs/ona/runners/gcp/gcp-runner-costs) | Infrastructure costs and optimization strategies |
| [Updating a runner](/docs/ona/runners/gcp/update-runner) | Terraform infrastructure upgrades and release notifications |
| [Warm pools](/docs/ona/projects/warm-pools) | Pre-initialized instances for near-instant environment startup |
| [Alerts & dashboards](/docs/ona/runners/gcp/alerts-and-dashboards) | Pre-built Grafana alerts and monitoring dashboards |
| [Troubleshooting](/docs/ona/runners/gcp/troubleshooting-runners) | Common problems and diagnostic steps |
# Using private Google Artifact Registry images
Source: https://ona.com/docs/ona/runners/gcp/private-gar-images
This guide explains how to use private Google Artifact Registry (GAR) images as Dev Container images when using GCP runners. With runner-native authentication, you can access private GAR repositories without manually managing credentials.
## Prerequisites
Before you begin, ensure you have:
* **GCP runners** deployed and configured for your Ona environments
* **GAR registry** in the same GCP project as your runners (or with appropriate cross-project access)
* **gcloud CLI** installed and authenticated with appropriate permissions to manage IAM policies
* **Runner name and project ID** from your Ona runner configuration
## Setting up Google Artifact Registry Access
### Step 1: Create Container Registry Secret
1. Navigate to **Project → Secrets → New Secret** in your Ona dashboard
2. Select **Container Registry Basic Auth** from the type dropdown
3. For the **Registry hostname**, enter your GAR registry hostname in the format: `[region]-docker.pkg.dev`
Examples:
* `us-central1-docker.pkg.dev` (for US Central region)
* `europe-west1-docker.pkg.dev` (for Europe West region)
* `asia-southeast1-docker.pkg.dev` (for Asia Southeast region)
4. When you enter a GAR registry hostname, the username and password fields will automatically be filled with `runner-native` to indicate that native runner authentication will be used
5. Click **Add**
**Runner-native Authentication**: When you enter a GAR hostname, Ona automatically detects this as a supported registry and enables runner-native authentication, eliminating the need for manual credential management.
### Step 2: Configure Service Account Permissions
Your GCP runner creates an environment VM service account that needs access to your GAR repositories.
#### Identify Your Environment Service Account
Your environment service account follows this naming pattern:
```
{RUNNER_NAME}-env-vm@{PROJECT_ID}.iam.gserviceaccount.com
```
For example, if your runner is named `gcp-runner-01` in project `my-project-123`, the service account would be:
```
gcp-runner-01-env-vm@my-project-123.iam.gserviceaccount.com
```
#### Grant Repository Access (Recommended)
Use the `gcloud` command to grant access to specific repositories:
```bash theme={null}
# Set your configuration variables
PROJECT_ID="your-project-id"
RUNNER_NAME="your-runner-name"
REGION="your-region"
REPO_NAME="your-repository-name"
# The environment VM service account (automatically created by your runner)
ENVIRONMENT_VM_SERVICE_ACCOUNT="${RUNNER_NAME}-env-vm@${PROJECT_ID}.iam.gserviceaccount.com"
# Grant repository access
gcloud artifacts repositories add-iam-policy-binding $REPO_NAME \
--location=$REGION \
--member="serviceAccount:${ENVIRONMENT_VM_SERVICE_ACCOUNT}" \
--role="roles/artifactregistry.reader"
```
#### Alternative: Project-level Access
For broader access, you can grant project-level permissions:
```bash theme={null}
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${ENVIRONMENT_VM_SERVICE_ACCOUNT}" \
--role="roles/artifactregistry.reader"
```
### Step 3: Configure Your Dev Container
Update your `.devcontainer/devcontainer.json` to use your private GAR image:
```json theme={null}
{
"name": "My Dev Container",
"image": "us-central1-docker.pkg.dev/my-project-123/my-repo/my-image:latest",
"features": {
// Your features here
}
}
```
## Required IAM roles
The minimum required role for accessing GAR repositories is:
```
roles/artifactregistry.reader
```
For more granular control, you can create a custom role with these specific permissions:
```
artifactregistry.repositories.downloadArtifacts
artifactregistry.repositories.get
artifactregistry.repositories.list
```
## Verification
To verify the permissions are correctly configured:
### Check Repository-level Permissions
```bash theme={null}
gcloud artifacts repositories get-iam-policy $REPO_NAME --location=$REGION
```
### Check Project-level Permissions
```bash theme={null}
gcloud projects get-iam-policy $PROJECT_ID \
--flatten="bindings[].members" \
--format="table(bindings.role)" \
--filter="bindings.members:${ENVIRONMENT_VM_SERVICE_ACCOUNT}"
```
### Verify Service Account Exists
```bash theme={null}
# List all service accounts in your project
gcloud iam service-accounts list --project=$PROJECT_ID
# Look for accounts matching the pattern: {RUNNER_NAME}-env-vm@{PROJECT_ID}.iam.gserviceaccount.com
```
## Limitations
* **GCP runners only**: GAR runner-native registry support is only available for GCP runners
* **Same project recommended**: Your GCP runners and GAR registry should be in the same project for simplest configuration
* **Environment recreation required**: Existing environments must be recreated to apply changes to GAR permissions
* **No automatic docker login**: Unlike basic auth registries, GAR doesn't automatically log you into the registry from within the environment. Use [gcloud auth](https://cloud.google.com/artifact-registry/docs/docker/authentication) or [Ona OIDC](/docs/ona/configuration/oidc) for additional registry access from within your environment
## Next steps
* Learn more about [GCP runner setup](/docs/ona/runners/gcp/setup)
* Explore [container registry secrets](/docs/ona/configuration/secrets/container-registry-secret) for other registry types
* Configure [OIDC authentication](/docs/ona/configuration/oidc) for additional cloud service access
## Troubleshooting
If you're experiencing image pull failures, verify:
1. **Service account name is correct**:
```bash theme={null}
# List all service accounts in your project
gcloud iam service-accounts list --project=$PROJECT_ID
```
2. **IAM permissions are correctly applied**:
```bash theme={null}
# Check repository-level permissions
gcloud artifacts repositories get-iam-policy $REPO_NAME --location=$REGION
```
3. **Repository exists and is accessible**:
```bash theme={null}
# List repositories in the region
gcloud artifacts repositories list --location=$REGION
```
If you see authentication errors in your environment logs:
* Ensure the GAR hostname format is correct: `[region]-docker.pkg.dev`
* Verify that your runner and registry are in the same project or have cross-project access configured
* Check that the service account has the minimum required role: `roles/artifactregistry.reader`
* Confirm the service account name matches the expected pattern
**"Failed to pull image"**
* Check that the image exists in the specified repository
* Verify the image tag is correct
* Ensure the service account has pull permissions
**"Authentication required"**
* Confirm the container registry secret is properly configured
* Verify the service account has the correct IAM roles
* Check that the GAR hostname matches your registry region
# Reference Architectures
Source: https://ona.com/docs/ona/runners/gcp/reference-architectures
The GCP Runner supports two load balancer modes. Choose the one that matches your network architecture and security requirements.
| | External Load Balancer | Internal Load Balancer |
| ----------------------- | -------------------------------------- | --------------------------------------- |
| **Access** | Internet-accessible | VPC and corporate network only |
| **Certificate storage** | Google Certificate Manager | Google Secret Manager |
| **Additional subnets** | None | Proxy subnet + routable subnet |
| **Corporate network** | Not required | VPN or Interconnect required |
| **Best for** | Teams accessing from various locations | Enterprise with strict network controls |
## External Load Balancer (Default)
Environments are accessible over the internet through Google Cloud's global load balancer. This is the simpler configuration. No additional networking infrastructure is required beyond a standard VPC subnet.
### Subnet requirements
| Subnet | Purpose | CIDR recommendation |
| ----------------- | ---------------------------------------- | ---------------------------------------------------------------- |
| **Runner subnet** | Hosts runner service and environment VMs | `/16` for non-routable ranges, `/24` minimum for routable ranges |
If the runner subnet does not have external internet access, enable [Private Google Access](https://cloud.google.com/vpc/docs/configure-private-google-access) so VMs can reach GCP services through Google's internal network.
### SSL/TLS certificate
* Store your certificate in **Google Certificate Manager**
* The certificate must include both the root domain and wildcard as Subject Alternative Names (SANs):
* `yourdomain.com`
* `*.yourdomain.com`
* Managed certificates or uploaded certificates are both supported
* Reference format: `projects/{project}/locations/global/certificates/{name}`
For the Terraform variables to configure this mode, see [Setup: External Load Balancer](/docs/ona/runners/gcp/setup#external-load-balancer-default).
## Internal Load Balancer
All traffic stays within your VPC and corporate network. Environments are not accessible from the internet. This mode requires corporate network connectivity (VPN, Interconnect, etc.) to your GCP VPC.
The architecture differs from the external mode because GCP's [internal passthrough Network Load Balancer](https://cloud.google.com/load-balancing/docs/internal) does not support TLS termination. TLS is instead terminated inside the Ona proxy component, which is why the certificate must be stored in Secret Manager (accessible to the proxy) rather than Certificate Manager. This also requires additional subnets:
* **Proxy subnet**: GCP provisions its own Envoy-based proxy infrastructure in this subnet to route traffic to the internal load balancer. This is a [GCP requirement for regional managed proxies](https://cloud.google.com/load-balancing/docs/proxy-only-subnets).
* **Routable subnet**: provides a routable IP address for the internal load balancer endpoint, reachable from your corporate network via VPN or Interconnect.
### Subnet requirements
The internal load balancer requires three subnets:
| Subnet | Purpose | CIDR recommendation | Routable from corporate network? |
| ------------------- | ---------------------------------------- | ---------------------------------------------------------------- | -------------------------------------------- |
| **Runner subnet** | Hosts runner service and environment VMs | `/16` for non-routable ranges, `/24` minimum for routable ranges | Not required |
| **Proxy subnet** | Reserved for internal LB proxy instances | `/26` minimum (64 IPs), GCP recommends `/23` | No |
| **Routable subnet** | Allocates the internal LB IP address | `/28` (16 IPs) | **Yes**, must be reachable from your network |
Additional subnet requirements:
* The **proxy subnet** must have its purpose set to `REGIONAL_MANAGED_PROXY`
* The **routable subnet** must have routes from your internal/on-premises network
* If the runner subnet lacks external internet access, enable [Private Google Access](https://cloud.google.com/vpc/docs/configure-private-google-access)
### SSL/TLS certificate
* Store your certificate in **Google Secret Manager** as a JSON object containing both the certificate and private key
* The certificate must include both SANs: `yourdomain.com` and `*.yourdomain.com`
* Reference format: `projects/{project}/secrets/{secret-name}`
* See [Setup: Internal Load Balancer](/docs/ona/runners/gcp/setup#internal-load-balancer) for the expected secret JSON format
For the Terraform variables to configure this mode, see [Setup: Internal Load Balancer](/docs/ona/runners/gcp/setup#internal-load-balancer).
### Additional requirements
* **Corporate network connectivity** to your GCP VPC (VPN, Interconnect, or similar)
* **DNS resolution** from your corporate network for the runner domain
* The proxy subnet and routable subnet must exist before running `terraform apply`
## Outbound connectivity
The runner and environment VMs need outbound internet access to reach the Ona management plane, container registries, IDE downloads, and other external services. See [Access Requirements: Network Connectivity](/docs/ona/runners/gcp/detailed-access-requirements#network-connectivity-requirements) for the full list of required endpoints.
How you provide this access depends on your network architecture:
| Strategy | When to use |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **External IP addresses** | Simplest option. Each VM gets a public IP and routes directly to the internet. Suitable when your security policy allows direct egress. |
| **Cloud NAT** | VMs use private IPs only. A [Cloud NAT gateway](https://cloud.google.com/nat/docs/overview) provides outbound internet access without exposing VMs publicly. Common for production deployments. |
| **HTTP/HTTPS proxy** | Route outbound traffic through a corporate proxy. Configure via the `proxy_config` Terraform variable. See [Setup: HTTP Proxy Configuration](/docs/ona/runners/gcp/setup#http-proxy-configuration). |
| **Private Service Connect** | Access specific Google APIs over private endpoints without internet egress. See [GCP Private Service Connect](https://cloud.google.com/vpc/docs/private-service-connect). |
If your VPC has no default internet route and you're not using Cloud NAT or a proxy, VMs will fail to pull container images, download IDE components, or connect to the Ona management plane. Ensure at least one egress path is configured before deployment.
For more on GCP egress options, see [Google Cloud network connectivity overview](https://cloud.google.com/vpc/docs/vpc#internet_access_reqs).
## Next steps
* [Setup guide](/docs/ona/runners/gcp/setup): deploy your GCP Runner with Terraform
* [Access Requirements](/docs/ona/runners/gcp/detailed-access-requirements): IAM permissions and network connectivity requirements
* [Troubleshooting](/docs/ona/runners/gcp/troubleshooting-runners): diagnose load balancer and networking issues
# Setup GCP runner
Source: https://ona.com/docs/ona/runners/gcp/setup
Deploy your GCP Runner using the [Terraform module](https://registry.terraform.io/modules/gitpod-io/ona-runner/google/latest). This guide walks through prerequisites, Terraform configuration, deployment, and verification.
## Prerequisites
Before starting, ensure you have:
1. **GCP Project** with billing enabled, sufficient [quotas](/docs/ona/runners/gcp/detailed-access-requirements#quota-requirements), and [required GCP APIs enabled](/docs/ona/runners/gcp/detailed-access-requirements#gcp-services-and-apis-required)
2. **VPC and subnet**: a custom VPC with a runner subnet. The runner subnet hosts both the runner service and environment VMs. Internal load balancers require [additional subnets](/docs/ona/runners/gcp/reference-architectures#internal-load-balancer).
**Optional: Private Google Access.** If your runner subnet does not have external internet access, enable [Private Google Access](https://cloud.google.com/vpc/docs/configure-private-google-access) on the subnet so VMs can reach GCP services through Google's internal network. See [GCP services and APIs required](/docs/ona/runners/gcp/detailed-access-requirements#gcp-services-and-apis-required) for the full list of services that need to be reachable.
3. **Domain name** that you control with DNS modification capabilities
4. **SSL/TLS certificate** with Subject Alternative Names (SANs) for both the root domain and wildcard: `yourdomain.com` and `*.yourdomain.com`. Storage location depends on your [load balancer mode](/docs/ona/runners/gcp/reference-architectures#ssltls-certificate).
5. **Terraform** >= 1.3 and **gcloud CLI** installed and authenticated
Haven't decided on a load balancer mode yet? [Compare external vs internal options](/docs/ona/runners/gcp/reference-architectures) before proceeding.
## Create runner in Ona
1. In the Ona dashboard, go to **Settings → Runners** and click **Set up a new runner**
2. Select **Google Cloud Platform** as the provider
3. Enter a **name** and click **Create**
The dashboard generates a Terraform configuration example with your **Runner ID**, **Runner Token**, and **API endpoint** pre-filled. Copy these values. You'll use them in the Terraform setup below.
Store the Runner Token securely. You cannot retrieve it again from the dashboard.
## Terraform module setup
Create a directory for your runner configuration and set up the following files.
**`main.tf`** references the Ona Terraform module with a GCS backend for state storage:
```hcl theme={null}
terraform {
backend "gcs" {
bucket = "your-terraform-state-bucket"
prefix = "ona-runner"
}
}
module "ona_runner" {
source = "gitpod-io/ona-runner/google"
version = "~> 1.0"
api_endpoint = var.api_endpoint
runner_id = var.runner_id
runner_token = var.runner_token
runner_name = var.runner_name
runner_domain = var.runner_domain
project_id = var.project_id
region = var.region
zones = var.zones
vpc_name = var.vpc_name
vpc_project_id = var.vpc_project_id
runner_subnet_name = var.runner_subnet_name
}
```
Using a [GCS backend](https://developer.hashicorp.com/terraform/language/backend/gcs) stores your Terraform state remotely, enabling team collaboration and protecting against local state loss. Create the bucket beforehand with versioning enabled.
**`variables.tf`** declares input variables. Add optional variables from the [advanced configuration](#advanced-configuration) section as needed:
```hcl theme={null}
variable "api_endpoint" {
type = string
}
variable "runner_id" {
type = string
}
variable "runner_token" {
type = string
sensitive = true
}
variable "runner_name" {
type = string
}
variable "runner_domain" {
type = string
}
variable "project_id" {
type = string
}
variable "region" {
type = string
}
variable "zones" {
type = list(string)
}
variable "vpc_name" {
type = string
}
variable "vpc_project_id" {
type = string
default = ""
}
variable "runner_subnet_name" {
type = string
}
```
**`terraform.tfvars`** contains the values from the Ona dashboard and your GCP project. See the sections below for the full variable reference.
## Required configuration variables
These variables are required for every GCP Runner deployment. Most of them are pre-filled in the Terraform configuration example shown in the Ona dashboard after you create the runner.
### Core Authentication Variables
These values are provided by the Ona dashboard when you create the runner.
| Variable | Description | Example Value | Required |
| --------------- | -------------------------------------------------------- | ----------------------------- | -------- |
| `api_endpoint` | Ona management plane API endpoint (from Ona dashboard) | `"https://app.gitpod.io/api"` | ✅ Yes |
| `runner_id` | Unique identifier for your runner (from Ona dashboard) | `"runner-abc123def456"` | ✅ Yes |
| `runner_token` | Authentication token for the runner (from Ona dashboard) | `"eyJhbGciOiJSUzI1NiIs..."` | ✅ Yes |
| `runner_name` | Display name for your runner | `"my-company-gcp-runner"` | ✅ Yes |
| `runner_domain` | Domain name for accessing development environments | `"dev.yourcompany.com"` | ✅ Yes |
The `api_endpoint` value is provided in the Ona dashboard when you create the runner. If your organization uses a [custom domain](/docs/ona/custom-domain), the endpoint will reflect that domain instead.
```hcl theme={null}
# terraform.tfvars - Core runner authentication (copy from Ona dashboard)
api_endpoint = "https://app.gitpod.io/api" # Ona management plane API
runner_id = "runner-abc123def456" # From Ona dashboard
runner_token = "eyJhbGciOiJSUzI1NiIs..." # From Ona dashboard
runner_name = "my-company-gcp-runner" # Descriptive name
runner_domain = "dev.yourcompany.com" # Your domain
```
### GCP Project and Location
Specify the GCP project and region where the runner infrastructure will be created.
| Variable | Description | Example Value | Required |
| ------------ | --------------------------------------------------- | ------------------------------------ | -------- |
| `project_id` | Your GCP project ID | `"your-gcp-project-123"` | ✅ Yes |
| `region` | GCP region for deployment | `"us-central1"` | ✅ Yes |
| `zones` | List of availability zones (2-3 recommended for HA) | `["us-central1-a", "us-central1-b"]` | ✅ Yes |
```hcl theme={null}
# terraform.tfvars - GCP project and location
project_id = "your-gcp-project-123"
region = "us-central1"
zones = ["us-central1-a", "us-central1-b", "us-central1-c"]
```
### Network and Ingress Configuration
Configure how inbound and outbound traffic reaches your runner by specifying your VPC, subnet, and load balancer settings.
| Variable | Description | Example Value | Required |
| -------------------- | ----------------------------------------------------- | --------------------------- | -------- |
| `vpc_name` | Name of your existing VPC | `"your-company-vpc"` | ✅ Yes |
| `runner_subnet_name` | Subnet where runner and environments will be deployed | `"dev-environments-subnet"` | ✅ Yes |
The runner subnet hosts both the runner service and environment VMs. Recommended CIDR: `/16` for non-routable ranges (large deployments) or `/24` minimum for routable ranges.
#### External Load Balancer (Default)
```hcl theme={null}
# terraform.tfvars
vpc_name = "your-company-vpc"
runner_subnet_name = "dev-environments-subnet"
loadbalancer_type = "external" # Optional, this is the default
certificate_id = "projects/your-project/locations/global/certificates/your-cert"
```
#### Internal Load Balancer
```hcl theme={null}
# terraform.tfvars
vpc_name = "your-company-vpc"
runner_subnet_name = "dev-environments-subnet"
loadbalancer_type = "internal"
routable_subnet_name = "internal-lb-subnet"
certificate_secret_id = "projects/your-project/secrets/ssl-cert-secret"
```
**Creating the certificate secret**
The `certificate_secret_id` must point to a Google Secret Manager secret containing both the certificate and private key as a JSON object:
```json theme={null}
{
"certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"privateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
}
```
Create the secret using `gcloud`, replacing the paths with your certificate and key files:
```bash theme={null}
jq -n \
--arg cert "$(cat your-cert.pem)" \
--arg key "$(cat your-key.pem)" \
'{"certificate": $cert, "privateKey": $key}' \
| gcloud secrets create ssl-cert-secret \
--project=your-project \
--data-file=- \
--replication-policy=automatic
```
The internal load balancer also requires a **proxy-only subnet** in your VPC with purpose set to `REGIONAL_MANAGED_PROXY`. This subnet is not a Terraform module variable. It must exist in your VPC before deployment. GCP uses it internally to allocate proxy instances for the load balancer.
[Learn more about internal load balancer requirements →](/docs/ona/runners/gcp/reference-architectures#internal-load-balancer)
## Advanced configuration
The settings below are for organizations with additional network or security requirements, such as corporate proxies, private CAs, encryption key management, or restricted IAM policies. Most deployments do not need these.
### HTTP Proxy Configuration
For environments behind corporate firewalls:
| Variable | Description | Example Value |
| -------------------------- | --------------------------------------------- | ------------------------------------ |
| `proxy_config.http_proxy` | HTTP proxy server URL | `"http://proxy.company.com:8080"` |
| `proxy_config.https_proxy` | HTTPS proxy server URL | `"https://proxy.company.com:8080"` |
| `proxy_config.no_proxy` | Comma-separated list of hosts to bypass proxy | `".company.com,localhost,127.0.0.1"` |
| `proxy_config.all_proxy` | All-protocol proxy server URL | `"http://proxy.company.com:8080"` |
```hcl theme={null}
# terraform.tfvars - HTTP proxy configuration for corporate environments
proxy_config = {
http_proxy = "http://proxy.company.com:8080"
https_proxy = "https://proxy.company.com:8080"
no_proxy = "localhost,127.0.0.1,metadata.google.internal,.company.com"
all_proxy = "http://proxy.company.com:8080"
}
```
### Custom CA Certificate
If your network uses a corporate proxy or internal services with certificates signed by a private Certificate Authority, configure the runner to trust your CA certificate:
| Variable | Description | Example Value |
| -------------------------- | ------------------------------------------- | ------------------------------------ |
| `ca_certificate.file_path` | Path to a CA certificate file | `"./certs/corporate-ca.pem"` |
| `ca_certificate.content` | CA certificate content (PEM-encoded string) | `"-----BEGIN CERTIFICATE-----\n..."` |
Provide either `file_path` or `content`, not both.
```hcl theme={null}
# terraform.tfvars - Option 1: Reference a CA certificate file
ca_certificate = {
file_path = "./certs/corporate-ca.pem"
}
# Option 2: Inline CA certificate content
# ca_certificate = {
# content = "-----BEGIN CERTIFICATE-----\nMIID...your-ca-cert...\n-----END CERTIFICATE-----"
# }
```
This is commonly needed alongside [HTTP Proxy Configuration](#http-proxy-configuration) when the proxy performs TLS inspection with a corporate CA.
### Customer-Managed Encryption Keys (CMEK)
For compliance with organizational encryption policies:
| Variable | Description | Default Value |
| -------------- | -------------------------------------------- | ------------- |
| `create_cmek` | Automatically create KMS keyring and key | `false` |
| `kms_key_name` | Existing KMS key (when create\_cmek = false) | `null` |
```hcl theme={null}
# terraform.tfvars - Option 1: Automatic CMEK setup (recommended)
create_cmek = true
# Option 2: Use existing KMS key
# create_cmek = false
# kms_key_name = "projects/your-project/locations/us-central1/keyRings/gitpod-keyring/cryptoKeys/gitpod-key"
```
For additional configurations when using pre-existing CMEK keys, refer to the [IAM configuration guide](https://github.com/gitpod-io/terraform-google-ona-runner/blob/main/docs/iam.md) in the Terraform module.
### Cross-Zone Restart
Enable cross-zone restart if stopped dual-disk environments should be able to restart in another zone when the original zone has no VM capacity.
When enabled, the runner makes a stopped dual-disk VM eligible for deletion after a 10-minute grace period instead of the default 4 hours. The runner preserves the detached data disk and starts a recovery snapshot after detachment.
A same-zone restart reattaches the disk. If that zone has no VM capacity and the snapshot is ready, the runner can recreate the data disk in another zone.
| Variable | Description | Default Value |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------- |
| `enable_cross_zone_restart` | Shortens stopped-VM retention and snapshots the preserved data disk for cross-zone recovery after a capacity error | `false` |
```hcl theme={null}
# terraform.tfvars
enable_cross_zone_restart = true
```
This option requires Terraform module v2.0.3 or later. Existing deployments keep their current behavior unless you enable it.
### Pre-Created Service Accounts
By default, the Terraform module creates and manages three service accounts for the runner components:
| Service Account | Purpose |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **runner** | Runner orchestrator. Manages environment lifecycle, compute instances, networking, secrets, build cache, and event processing |
| **environment\_vm** | Environment VMs. Reads container images, writes logs and metrics |
| **proxy\_vm** | Proxy VMs. Routes traffic to environments, reads secrets and container images |
If your organization requires service accounts to be created externally (e.g., by a central IAM team), you can provide pre-created service accounts instead. The module skips creating each supplied service account and uses the one you provide.
By default, your IAM team must assign the custom roles, general project-level roles, and `roles/iam.serviceAccountUser` policies. Set `attach_iam_policies` to `true` to let the Terraform module manage those permissions. This mode requires the Terraform deployer to have permission to create custom roles and update IAM policies, but the IAM team only needs to create the service accounts.
```hcl theme={null}
# terraform.tfvars - Pre-created service accounts (all optional, provide only the ones you manage externally)
pre_created_service_accounts = {
runner = "gitpod-runner@your-project.iam.gserviceaccount.com"
environment_vm = "gitpod-env@your-project.iam.gserviceaccount.com"
proxy_vm = "gitpod-proxy@your-project.iam.gserviceaccount.com"
attach_iam_policies = true
}
```
`attach_iam_policies` defaults to `false`. You can provide a subset of the service accounts. The module creates any account left empty. See the [IAM configuration guide](https://github.com/gitpod-io/terraform-google-ona-runner/blob/main/docs/iam.md) for the roles required by each mode.
### Custom Images
Some enterprise networks do not allow pulling container images from external registries. In these cases, you can point the runner at images hosted in your own internal registry.
**Discouraged unless your network policy strictly requires it.** Ona maintains all runner images in a public registry with regular CVE scanning and patching. Custom images break automatic updates and delay security patches. You must sync every release manually. If possible, [allowlist Ona's registry](/docs/ona/runners/gcp/detailed-access-requirements#container-registries) instead.
| Variable | Description | Example Value |
| ---------------------------------- | ---------------------------------- | ----------------------------------------- |
| `custom_images.runner_image` | Custom runner container image | `"gcr.io/your-project/runner:v1.0"` |
| `custom_images.proxy_image` | Custom proxy container image | `"gcr.io/your-project/proxy:v1.0"` |
| `custom_images.prometheus_image` | Custom Prometheus image | `"gcr.io/your-project/prometheus:latest"` |
| `custom_images.docker_config_json` | Docker registry credentials (JSON) | `jsonencode({...})` |
```hcl theme={null}
# terraform.tfvars - Custom images configuration
custom_images = {
runner_image = "gcr.io/your-project/custom-runner:v1.0"
proxy_image = "gcr.io/your-project/custom-proxy:v1.0"
prometheus_image = "gcr.io/your-project/prometheus:latest"
# Docker registry authentication (JSON format)
docker_config_json = jsonencode({
auths = {
"gcr.io" = {
auth = base64encode("_json_key:${file("service-account-key.json")}")
}
}
})
# Set to true for insecure registries (testing only)
insecure = false
}
```
If you must use custom images, set up an automated pipeline to sync images from Ona's stable channel to your internal registry (e.g., Artifactory). Contact Ona support for guidance on image synchronization and release notifications.
### Shared VPC
If your organization uses a [GCP Shared VPC](https://cloud.google.com/vpc/docs/shared-vpc) where the VPC is hosted in a separate host project, set `vpc_project_id` to the project that owns the VPC. When omitted, the module assumes the VPC is in the same project as the runner (`project_id`).
| Variable | Description | Example Value |
| ---------------- | ------------------------------------------ | --------------------------- |
| `vpc_project_id` | Project ID where the Shared VPC is located | `"shared-vpc-host-project"` |
```hcl theme={null}
# terraform.tfvars - Shared VPC configuration
project_id = "runner-service-project" # Project where runner resources are created
vpc_project_id = "shared-vpc-host-project" # Project that hosts the Shared VPC
vpc_name = "shared-company-vpc" # VPC name in the host project
runner_subnet_name = "dev-environments-subnet" # Subnet shared to the service project
```
When using Shared VPC, the runner's service project must be [attached as a service project](https://cloud.google.com/vpc/docs/provisioning-shared-vpc#create-shared) to the host project, and the subnets used by the runner must be shared with the service project. The service account running Terraform needs `compute.networkUser` on the shared subnets in the host project.
### Project Metadata Mode
By default the module uses `google_compute_project_metadata`, which is authoritative and removes any project metadata keys not declared in the module. Set `use_authoritative_project_metadata = false` to use per-key `google_compute_project_metadata_item` resources instead, which only manage `enable-oslogin` and `gitpod-runner-id`.
```hcl theme={null}
use_authoritative_project_metadata = false
```
Before applying with `use_authoritative_project_metadata = false` on an existing deployment, migrate the Terraform state:
```bash theme={null}
terraform state rm 'module.ona_runner.google_compute_project_metadata.runner_metadata'
terraform import 'module.ona_runner.google_compute_project_metadata_item.enable_oslogin[0]' 'projects//enable-oslogin'
terraform import 'module.ona_runner.google_compute_project_metadata_item.runner_id[0]' 'projects//gitpod-runner-id'
terraform plan # should show no changes
```
Replace `` with your GCP project ID. Adjust the module path if yours differs from `ona_runner`.
### Labels
Apply [GCP labels](https://cloud.google.com/resource-manager/docs/creating-managing-labels) to all resources created by the module. Labels are useful for cost attribution, filtering in billing reports, and organizational policies.
```hcl theme={null}
# terraform.tfvars
labels = {
team = "platform"
environment = "production"
cost-center = "engineering"
}
```
For details on using labels for cost tracking and budgeting, see [Costs & Budgeting: Adding labels to Compute Engine instances](/docs/ona/runners/gcp/gcp-runner-costs#adding-labels-to-compute-engine-instances).
## Deploy
Initialize Terraform to download the module, then validate, plan, and apply:
```bash theme={null}
terraform init
terraform validate
terraform plan -out=tfplan
terraform apply tfplan
```
Deployment typically takes 15–20 minutes. The Redis instance creation is usually the longest step.
## Post-deployment
After `terraform apply` completes, retrieve the load balancer IP and configure DNS:
```bash theme={null}
terraform output load_balancer_ip
```
Create A records for both the root domain and wildcard pointing to this IP:
```
yourdomain.com. A
*.yourdomain.com. A
```
For internal load balancers, ensure your corporate DNS servers can resolve these records and your network can route to the internal IP.
Once DNS propagates, verify the runner is healthy:
```bash theme={null}
curl -k https://yourdomain.com/_health
# Expected: {"status":"ok"} with HTTP 200
```
Then confirm the runner shows as **Online** in the Ona dashboard under **Settings → Runners**.
## Next steps
With your GCP Runner successfully deployed and verified:
* [Configuring Repository Access](/docs/ona/runners/configuring-repository-access) - Set up access to your Git repositories and authentication
* [Private GAR Images](/docs/ona/runners/gcp/private-gar-images) - Configure access to private Google Artifact Registry
* [Model access](/docs/ona/agents/llm-providers/overview) - Configure supported OpenAI model access for Codex Agent on this runner
* [Troubleshooting Guide](/docs/ona/runners/gcp/troubleshooting-runners) - Troubleshooting and monitoring guide
# Troubleshooting GCP runners
Source: https://ona.com/docs/ona/runners/gcp/troubleshooting-runners
Learn how to troubleshoot GCP runners.
If you encounter any issues while setting up or operating a Runner, please follow these steps:
* Review [the common problems](#common-problems).
* If the issue persists, [reach out to support](#contacting-support).
## Contacting support
To start a support chat, open **Support** from the organization menu in the application. When contacting support, please include the following information:
* Any error messages and relevant screenshots.
* [Runner ID and Version](#copy-runner-id-and-version) and [GCP Region](#find-terraform-state).
* [Runner Logs](#retrieve-runner-logs-compute-engine-logs).
### Copy Runner ID and Version
* Navigate to **Settings → Runners**.
* Locate your Runner card.
* Click `...` in the top right corner and select `Copy ID`.
* The Runner Version is displayed as the last item in the menu.
### Find Terraform State
* Navigate to **Settings → Runners**.
* Open the Runner card to find the deployment details including region and project ID.
* Check your Terraform state file or remote state backend for additional deployment information.
### Retrieve Runner Logs (Compute Engine Logs)
You can adjust the log level of your Runner from the Runner Configuration section to get more detailed logs for troubleshooting. See [GCP Runner setup](/docs/ona/runners/gcp/setup) for log level configuration options.
#### Using GCP Console
To view the logs for the Runner using the GCP Console:
* Navigate to [the GCP Compute Engine console](https://console.cloud.google.com/compute/instances).
* Locate the runner instances by filtering for your runner name or project.
* Select the instance associated with the Runner.
* Go to the **Logs** tab or click **View logs** to access Cloud Logging.
* Filter logs by the runner service or container name.
Sample query to find instance logs:
```
resource.type=gce_instance AND
labels.instance_name=~".*(proxy|runner).*"
```
Sample query to find container logs:
```
jsonPayload."cos.googleapis.com/container_name"=~"gitpod-proxy|gitpod-runner"
```
Runner instances have multiple containers: one for the Runner itself and another for monitoring; we need the former.
#### Using gcloud CLI
To look up the instance name and view logs using gcloud CLI, follow these commands:
1. To list all instances and find your runner and proxy instances by name pattern:
```bash theme={null}
gcloud compute instances list --filter="labels.gitpod-type~'.*runner.*'"
gcloud compute instances list --filter="labels.gitpod-type~'.*proxy.*'"
```
2. To view logs for a specific instance:
```bash theme={null}
gcloud logging read "resource.type=gce_instance AND labels.instance_name=INSTANCE_NAME" --limit=50
```
3. To view logs for the runner or proxy service specifically:
```bash theme={null}
gcloud logging read 'resource.type="gce_instance" AND jsonPayload."cos.googleapis.com/container_name"="gitpod-proxy"' --limit=50
```
### Monitoring and Metrics
If you have configured metrics collection, your monitoring system will receive Runner metrics. The GCP Runner includes Prometheus metrics collection on port 9090. For information on configuring metrics collection, see [GCP Runner setup](/docs/ona/runners/gcp/setup).
## Common problems
Network misconfigurations and IAM permission issues are the most frequent causes of installation issues. Please refer to the [infrastructure prerequisites](/docs/ona/runners/gcp/detailed-access-requirements) to ensure all requirements are met. Below are common problems along with their diagnostics.
### Terraform Deployment Fails
* **Symptoms:**
* Terraform apply fails with resource creation errors.
* Error messages related to missing VPC, subnets, or insufficient permissions.
* Terraform state shows failed resource creation with status reasons:
* `Error creating instance: googleapi: Error 400: Invalid value for field 'resource.networkInterfaces[0].subnetwork'`
* `Error creating forwarding rule: googleapi: Error 403: Insufficient Permission`
* `Error creating service account: googleapi: Error 403: Permission denied`
* **Diagnostics:**
* Verify your service account has all required IAM roles from the [Access Requirements](/docs/ona/runners/gcp/detailed-access-requirements) page.
* Ensure the VPC and subnet specified in `terraform.tfvars` exist and are accessible.
* Check that the specified zones are available in your selected region.
* For internal load balancers, verify the proxy-only subnet exists with purpose `REGIONAL_MANAGED_PROXY`.
### Runner Instance Fails to Start
* **Symptoms:**
* Terraform deployment succeeds but runner instances fail to start or remain unhealthy.
* Health check validation fails during Terraform apply.
* Runner instances show as "RUNNING" but fail health checks.
* Cloud Logging shows container startup errors or authentication failures.
* **Diagnostics:**
* Verify that the VPC has **Cloud NAT** or **external IP addresses** configured for internet access.
* Check that firewall rules allow the required outbound traffic to Ona services.
* Ensure the runner token and runner ID are correct and haven't expired.
* For proxy environments, verify the proxy configuration is correct and accessible.
* Check that required container images are accessible from your project.
### Machine Type Not Available
If you encounter an error stating that the requested machine type is unavailable in a specific zone (e.g., "The zone 'projects/PROJECT\_ID/zones/us-central1-c' does not have enough resources available to fulfill the request"), this is often due to regional or zone-specific availability constraints within GCP.
Some zones may experience resource shortages more frequently. If possible, avoid using single zones exclusively and instead deploy your runners across multiple zones for better availability.
Here's how you can address this:
1. **Deploy to a Different Region**:
* Some machine types may be unavailable in certain regions or zones due to resource constraints. Refer to [GCP machine type availability](https://cloud.google.com/compute/docs/regions-zones) for details. If necessary, deploy runners to use a different GCP region that supports your preferred machine type.
2. **Select Multiple Zones**:
* When configuring your Terraform deployment, ensure that you specify multiple zones in the `zones` variable. For example, instead of restricting your deployment to only `us-central1-c`, include zones like `us-central1-a` and `us-central1-b` to improve availability.
* You can update the `zones` variable in your `terraform.tfvars` and run `terraform apply` to update the deployment.
3. **Use an Alternate Machine Type**:
* If the desired machine type (e.g., `n2-standard-4`) is unavailable, consider using a different machine type, such as `e2-standard-4` or `n1-standard-4`, which may have better availability.
* To update, modify the `runner_vm_config.machine_type` in your Terraform configuration and apply the changes.
4. **Retry Later**:
* Machine type availability can be transient. If none of the above options resolve the issue, wait and try again later, as GCP resources might become available after a brief period.
### Unexpected Costs
* **Symptoms:**
* You notice unexpected charges in your GCP bill that you believe are related to the Runner infrastructure.
* You continue receiving bills for resources even after destroying the Terraform deployment.
* **Diagnostics:**
* Use the [GCP Billing console](https://console.cloud.google.com/billing) to investigate the specific GCP resources contributing to the charges.
* After running `terraform destroy`, verify that all resources have been fully deleted. See [Delete runner → Check for leftovers](/docs/ona/runners/gcp/update-runner#4-check-for-leftovers) for `gcloud` commands to find residual Compute Engine instances and disks, load balancer components, Cloud Storage buckets, Memorystore Redis instances, snapshots, and reserved IP addresses.
### Load Balancer Connectivity Issues
* **Symptoms:**
* Cannot access the runner domain or environments through the load balancer.
* Health checks fail for the load balancer backend services.
* SSL/TLS certificate errors when accessing the runner domain.
* DNS resolution fails for the runner domain.
* **Diagnostics:**
* For **internal load balancers**: Verify that your corporate network has routing to the VPC and can reach the internal IP address.
* For **external load balancers**: Check that DNS records point to the correct external IP address.
* Verify SSL certificate configuration:
* For internal LB: Check that the certificate is properly stored in Secret Manager
* For external LB: Verify the Certificate Manager certificate is valid and covers your domain
* Test connectivity from different network locations to isolate routing issues.
* Check firewall rules allow HTTPS traffic (port 443) to the load balancer.
### IAM Permission Issues
* **Symptoms:**
* Terraform deployment fails with permission denied errors.
* Runner instances cannot access required GCP services (Secret Manager, Cloud Storage, etc.).
* Error messages like `Error 403: Insufficient Permission` or `Permission denied`.
* **Diagnostics:**
* Verify your deployment service account has all required roles from the [Access Requirements](/docs/ona/runners/gcp/detailed-access-requirements) page.
* Check that service accounts created by Terraform have the correct IAM bindings.
* For organizations with custom IAM policies, ensure they don't block required permissions.
* Test service account permissions using `gcloud auth activate-service-account` and attempting the failing operations manually.
### Network Connectivity Issues
If you experience connectivity issues with your GCP Runner, follow these troubleshooting steps to diagnose and resolve common networking problems.
#### Common Network Issues
If you experience connectivity issues:
1. **Verify firewall rules**
* Ensure port 29222 is open for SSH access to development environments
* Check that outbound rules allow HTTPS traffic to required endpoints
* Verify internal communication ports are allowed between runner components
2. **Check VPC and subnet configuration**
* Confirm Private Google Access is enabled on the runner subnet
* Verify Cloud NAT or external IP addresses are configured for internet access
* Ensure proxy-only subnet exists for internal load balancers
3. **Validate DNS resolution**
* Test DNS resolution for `app.gitpod.io` and required endpoints
* Verify corporate DNS can resolve your runner domain
* Check that VPC DNS settings are properly configured
4. **Test connectivity to Ona services**
* From a Compute Engine instance in your runner's subnet, test connectivity to required endpoints
* Use tools like `curl` or `telnet` to verify connectivity
#### Health Endpoint Connectivity Test
Test the health endpoint to verify network connectivity and load balancer functionality:
```bash theme={null}
# Test health endpoint connectivity (returns HTTP 200 on success)
curl -v https://your-domain.com/_health
# For internal load balancers, test from within your corporate network
curl -k https://your-internal-domain.com/_health
```
Replace `your-domain.com` with your actual domain name configured during setup. A successful response returns HTTP 200 status code, indicating that:
* DNS resolution is working correctly
* Load balancer is accessible from your network
* SSL/TLS certificate is properly configured
* Basic network connectivity is established
If this test fails, check:
* DNS configuration and propagation
* Firewall rules allowing HTTPS traffic
* Load balancer health and backend service status
* SSL certificate validity and domain matching
#### Required Endpoints Connectivity Test
Test connectivity to these critical endpoints from your runner's subnet:
```bash theme={null}
# Test HTTPS connectivity to Ona services
curl -I https://app.gitpod.io
curl -I https://app.gitpod.io/releases/cli/stable/manifest.json
# Test connectivity to GCP services
curl -I https://storage.googleapis.com
curl -I https://secretmanager.googleapis.com
```
#### Restarting Runner Instances After Networking Changes
After applying networking changes (such as firewall rule updates, VPC modifications, or proxy configurations), you may need to restart the runner instances to ensure the changes take effect.
##### Using the GCP Console
1. Navigate to the [GCP Compute Engine console](https://console.cloud.google.com/compute/instances)
2. Filter instances by your runner name or project
3. Select the runner instances you want to restart
4. Click **Stop** and wait for instances to stop completely
5. Click **Start** to restart the instances with updated networking configuration
6. The managed instance group will automatically recreate instances if needed
##### Using gcloud CLI
You can also restart runner instances using the gcloud CLI:
```bash theme={null}
# List runner instances
gcloud compute instances list --filter="name~'.*runner.*'"
# Stop instances (they will be automatically recreated by the managed instance group)
gcloud compute instances delete INSTANCE_NAME --zone=ZONE_NAME
# Or restart the entire managed instance group
gcloud compute instance-groups managed rolling-action restart INSTANCE_GROUP_NAME --region=REGION
```
##### Using Terraform
For a complete refresh of the deployment:
```bash theme={null}
# Recreate all instances with updated configuration
terraform apply -replace="google_compute_region_instance_group_manager.runner"
terraform apply -replace="google_compute_region_instance_group_manager.proxy"
```
#### Verification Steps
After making networking changes and restarting instances:
1. **Check Runner status in Ona**
* Go to **Settings → Runners** in your Ona dashboard
* Verify the Runner shows as "Connected"
2. **Test Environment creation**
* Create a new Environment using the Runner
* Verify the Environment starts successfully
3. **Monitor Cloud Logging**
* Check Compute Engine logs for any connectivity errors
* Look for successful connections to Ona services
### Proxy Configuration Issues
* **Symptoms:**
* Runner instances cannot reach external services through corporate proxy.
* Container image pulls fail through proxy.
* SSL/TLS certificate validation errors in proxy environments.
* **Diagnostics:**
* Verify proxy configuration in `terraform.tfvars` includes all required settings:
* `http_proxy`, `https_proxy`, `no_proxy` variables
* Check that `no_proxy` includes required internal domains and IP ranges.
* For custom CA certificates, verify the certificate is properly configured and accessible.
* Test proxy connectivity from a test instance in the same subnet.
### CMEK Encryption Issues
* **Symptoms:**
* Terraform fails to create encrypted resources.
* Error messages related to KMS key access or encryption.
* Resources fail to start due to encryption key unavailability.
* **Diagnostics:**
* Verify KMS key exists and is in the correct region.
* Check that service accounts have `roles/cloudkms.cryptoKeyEncrypterDecrypter` permission on the KMS key.
* For automatically created CMEK keys, ensure the deployment service account has KMS admin permissions.
* Verify the key is not disabled or scheduled for destruction.
# Upgrade and delete runner
Source: https://ona.com/docs/ona/runners/gcp/update-runner
Terraform infrastructure upgrades, release notifications, and deletion for GCP runners.
The GCP runner updates itself automatically for application-level changes. For details on how automatic updates work and how to configure update windows, see [Automated updates](/docs/ona/runners/runner-updates).
This page covers GCP-specific update procedures: release notifications and Terraform infrastructure upgrades.
## Release Notifications
Ona publishes Pub/Sub messages when new stable GCP runner releases are available. Subscribe to receive push notifications instead of polling for updates. This is useful for triggering CI pipelines, syncing [custom images](/docs/ona/runners/gcp/setup#custom-images), or alerting your infrastructure team when a Terraform upgrade is needed.
### Topic
| Property | Value |
| ----------------- | ------------------------------------------------------------ |
| Project | `gitpod-next-production` |
| Topic | `projects/gitpod-next-production/topics/gcp-runner-releases` |
| Message retention | 7 days |
| Access | Any authenticated GCP user can subscribe |
### Subscribing with gcloud
```bash theme={null}
# Create a pull subscription in your project
gcloud pubsub subscriptions create ona-runner-releases \
--project=YOUR_PROJECT_ID \
--topic=projects/gitpod-next-production/topics/gcp-runner-releases \
--ack-deadline=60
# Pull messages
gcloud pubsub subscriptions pull ona-runner-releases \
--project=YOUR_PROJECT_ID \
--auto-ack \
--limit=10
```
### Subscribing with Terraform
```hcl theme={null}
resource "google_pubsub_subscription" "ona_runner_releases" {
name = "ona-runner-releases"
project = var.project_id
topic = "projects/gitpod-next-production/topics/gcp-runner-releases"
ack_deadline_seconds = 60
# Optional: receive only CI-published messages (skip GCS notification duplicates)
# filter = "attributes.source = \"ci_stable_promotion\""
# Optional: retry policy
retry_policy {
minimum_backoff = "10s"
maximum_backoff = "600s"
}
}
```
For push subscriptions (HTTP webhook), set `push_config.push_endpoint` to your endpoint URL.
### Message format
Each message includes attributes for filtering:
* `event_type`: `release.stable`
* `version`: release version string (e.g., `20250115.0`)
* `source`: `ci_stable_promotion` (release promoted to stable) or `gcs_notification` (stable manifest updated in GCS)
The payload contains the release manifest with image references, download URLs, and change context:
```json theme={null}
{
"version": "20250115.0",
"commit": "abc123def",
"release_date": "2025-01-15T00:30:00Z",
"infrastructure_version": "latest",
"proxy_image": "us-docker.pkg.dev/gitpod-next-production/gitpod-next/gitpod-proxy:20250115.0",
"runner_image": "us-docker.pkg.dev/gitpod-next-production/gitpod-next/gitpod-gcp-runner:20250115.0",
"prometheus_image": "us-docker.pkg.dev/gitpod-next-production/gitpod-next/prometheus:v3.5.0",
"terraform_changes": [
"- Add network firewall rule for proxy health checks (a1b2c3d)",
"- Update default machine type to n2d-standard-16 (e4f5g6h)"
],
"iam_changes_detected": false
}
```
Key fields:
| Field | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `terraform_changes` | Terraform module commits since the previous release (empty if none). When non-empty, a `terraform apply` may be needed. |
| `iam_changes_detected` | `true` if IAM-related files changed. Signals that IAM configuration or [pre-created service accounts](/docs/ona/runners/gcp/setup#pre-created-service-accounts) may need updating. |
## Updating Infrastructure
Certain updates, particularly those involving significant infrastructural changes, cannot be applied automatically. Follow these steps to apply updates:
1. Navigate to the directory containing your runner Terraform configuration.
2. Update the `version` constraint in your `main.tf` module block to allow the new version. Check the [Terraform registry](https://registry.terraform.io/modules/gitpod-io/ona-runner/google/latest) for available versions.
```hcl theme={null}
module "ona_runner" {
source = "gitpod-io/ona-runner/google"
version = "~> 1.0" # Update this constraint as needed
# ...
}
```
3. Re-initialize Terraform to fetch the new module version:
```bash theme={null}
terraform init -upgrade
```
4. Review the planned changes before applying:
```bash theme={null}
terraform plan -out=tfplan
```
Carefully review the output for:
* New resources being created
* Resources being modified or replaced
* Any unexpected deletions
5. Apply the updates:
```bash theme={null}
terraform apply tfplan
```
6. Verify the runner status in the Ona dashboard under **Settings → Runners** to confirm the update was successful.
## Delete runner
Deleting a GCP runner is a two-step process: disconnect the runner from Ona, then destroy the GCP infrastructure with Terraform.
Deletion is permanent. Active environments are stopped and discarded, and any uncommitted work or ephemeral data on environment VMs is lost. Push anything you need to keep before starting.
### 1. Disconnect the runner in Ona
1. Go to **Settings → Runners** and select **Delete** from the runner's menu.
2. The runner enters **Pending deletion** and stops all environments attached to it.
3. Once environments are fully deleted, the runner record is removed from Ona (this can take a few minutes).
This step stops Ona from scheduling new work on the runner but does not remove any GCP resources. Those remain in your project until you run `terraform destroy`.
### 2. Destroy the GCP infrastructure
From the directory containing your runner Terraform configuration:
```bash theme={null}
terraform destroy
```
Review the plan carefully before confirming. `terraform destroy` removes everything the module created, including:
* Compute Engine instance templates, managed instance groups, and autoscalers for the runner and proxy VMs
* Load balancer components (forwarding rules, backend services, health checks, URL maps)
* Memorystore for Redis cluster and its Private Service Connect policy
* Cloud Storage buckets (`-runner-assets` and, if agents are enabled, `-agent-storage`)
* Artifact Registry repository used by the runner
* Secret Manager secrets (runner token, runner secrets key, Redis credentials, metrics config)
* Pub/Sub topics and subscriptions used for compute lifecycle events
* Firewall rules and module-created service accounts
* KMS keyring and key, if `create_cmek = true`
Deployment typically takes 15–20 minutes to provision; destruction is usually faster but can take several minutes, mostly waiting for the Redis cluster and load balancer to tear down.
### 3. Resources Terraform does not delete
A clean `terraform destroy` removes everything the module owns, but several categories of resources are deliberately **not** managed by the module and must be cleaned up manually if you no longer need them:
* **VPC, subnets, and Cloud NAT**. You created these before deployment (see [Setup prerequisites](/docs/ona/runners/gcp/setup#prerequisites)). They are not part of the module.
* **Proxy-only subnet** (internal load balancer deployments). The `REGIONAL_MANAGED_PROXY` subnet you created for the internal LB.
* **DNS records** for `yourdomain.com` and `*.yourdomain.com` pointing at the load balancer IP (see [Post-deployment](/docs/ona/runners/gcp/setup#post-deployment)).
* **SSL/TLS certificate**. The Certificate Manager certificate (external LB) or the Secret Manager secret (internal LB) you created outside the module.
* **GCS bucket holding Terraform state**. If you used a [remote backend](/docs/ona/runners/gcp/setup#terraform-module-setup), the state bucket persists after `terraform destroy`.
* **Pre-created service accounts**. If you supplied any via [`pre_created_service_accounts`](/docs/ona/runners/gcp/setup#pre-created-service-accounts), those are owned by your IAM team and are not destroyed.
* **Pre-existing KMS key**. If you used `create_cmek = false` and supplied a `kms_key_name`, the key stays. Only keys created by the module (`create_cmek = true`) are destroyed.
* **Release Pub/Sub subscriptions**. Any subscription you created to Ona's release topic (see [Release Notifications](#release-notifications)) lives in your project and is independent of the module.
### 4. Check for leftovers
After `terraform destroy` completes, verify no runner resources remain before closing out the project. This is the most common source of unexpected costs post-deletion.
Filter by the module's `managed-by=terraform` and `gitpod-runner-id=` labels, which are applied to all runner-owned resources:
```bash theme={null}
# Compute Engine: instances, disks, instance templates, instance groups
gcloud compute instances list \
--project=YOUR_PROJECT_ID \
--filter="labels.gitpod-runner-id=YOUR_RUNNER_ID"
gcloud compute disks list \
--project=YOUR_PROJECT_ID \
--filter="labels.gitpod-runner-id=YOUR_RUNNER_ID"
# Environment snapshots (persistent disk snapshots and machine images used for
# environment persistence and restore, safe to delete once the runner is gone)
gcloud compute snapshots list \
--project=YOUR_PROJECT_ID \
--filter="labels.gitpod-runner-id=YOUR_RUNNER_ID"
gcloud compute images list \
--project=YOUR_PROJECT_ID \
--filter="labels.gitpod-runner-id=YOUR_RUNNER_ID"
# Storage buckets
gcloud storage buckets list \
--project=YOUR_PROJECT_ID \
--filter="labels.gitpod-runner-id=YOUR_RUNNER_ID"
# Secret Manager secrets
gcloud secrets list \
--project=YOUR_PROJECT_ID \
--filter="labels.gitpod-runner-id=YOUR_RUNNER_ID"
# Load balancer forwarding rules and reserved static IPs
gcloud compute forwarding-rules list \
--project=YOUR_PROJECT_ID \
--filter="description~YOUR_RUNNER_ID OR name~YOUR_RUNNER_ID"
gcloud compute addresses list \
--project=YOUR_PROJECT_ID \
--filter="name~YOUR_RUNNER_ID"
```
Environment VMs and their persistent disks are tagged with `gitpod-type=environment` rather than the runner labels above. If you see leftover disks, instances, or snapshots with `gitpod-type=environment` or names starting with `env-`, these are per-environment resources. The runner normally cleans them up when environments are deleted. If the runner was force-deleted before draining, you may need to remove them manually.
Delete any remaining resources through the [GCP Console](https://console.cloud.google.com/) or `gcloud`. Pay particular attention to:
* **Persistent disks** from environments that were not cleanly terminated. These continue to incur storage costs.
* **Reserved static IP addresses** that were not released.
* **Forwarding rules and backend services** from the load balancer.
* **Storage buckets**. The runner assets bucket has `uniform_bucket_level_access` and `public_access_prevention` enforced, but it may still contain objects you need to delete first with `gcloud storage rm --recursive gs://BUCKET_NAME`.
### 5. Final verification
Confirm deletion in two places:
1. **Ona dashboard**. **Settings → Runners** no longer lists the runner.
2. **GCP Billing console**. [Check that billable resources are no longer being reported](https://console.cloud.google.com/billing) against the runner's labels after 24 hours.
If billing persists, re-run the leftover checks above and inspect the [Billing Reports](https://console.cloud.google.com/billing/reports) grouped by label to identify the resource driving the cost.
# Ona managed metrics
Source: https://ona.com/docs/ona/runners/managed-metrics
Let Ona monitor your runner health with curated operational metrics
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.Want to send metrics to your own observability stack? See [Custom metrics pipeline](/docs/ona/runners/monitoring-and-metrics).
Ona managed metrics lets you opt in to having Ona monitor your runner's operational health. When enabled, the runner pushes a curated set of Prometheus metrics to the Ona management plane, where the Ona team uses them to detect degradation and catch problems before they affect your developers.
This is independent of the [custom metrics pipeline](/docs/ona/runners/monitoring-and-metrics), where you configure your own Prometheus remote write endpoint. Both can run simultaneously: managed metrics go to Ona, self-managed metrics go to your own observability stack.
## Why enable managed metrics
Without metrics visibility, Ona cannot detect runner issues until you report them. Managed metrics close this gap:
* **Proactive monitoring:** Ona detects degraded runners, resource exhaustion, and elevated error rates before developers are impacted.
* **Faster incident resolution:** When you contact support, the Ona team already has the operational context they need.
* **Zero setup on your side:** No Prometheus endpoint to configure, no dashboards to build. Toggle it on and the runner handles the rest.
* **Non-sensitive data only:** The curated metric set contains only operational counters, gauges, and histograms. No user data, source code, or secrets are ever sent.
## Enabling managed metrics
1. Go to **Settings → Runners**
2. Select your runner
3. Toggle **Ona managed metrics**
The setting saves immediately. No additional confirmation is needed.
Metrics begin flowing within 60 seconds. No additional network configuration is required. The runner pushes metrics to the management plane over the same connection it already uses.
## What metrics are reported
The curated metric set answers: "Is this runner healthy and performing well?" Metrics are filtered to a hardcoded allowlist in the runner binary. Adding or removing metrics requires a runner release, which provides a natural review gate.
### Environment lifecycle
| Metric | Type | Description |
| ------------------------------------------------------------ | --------- | ------------------------------------------------------------------------------------------------------------- |
| `gitpod_runnerkit_active_instances` | Gauge | Current environment count by state |
| `gitpod_runnerkit_environment_operation_duration_seconds` | Histogram | Duration of environment operations |
| `gitpod_runnerkit_environment_start_retry_attempts_total` | Counter | Environment start fallback dispatches after a capacity rejection (`reason="capacity"`) |
| `gitpod_runnerkit_environment_start_terminal_failures_total` | Counter | Environment start sessions that ended in failure (`reason="capacity_exhausted"`, `"provider"`, or `"system"`) |
| `gitpod_runnerkit_function_calls_total` | Counter | Total function calls by function name |
| `gitpod_runnerkit_function_errors_total` | Counter | Total function errors by function name |
### Supervisor connectivity
| Metric | Type | Description |
| ------------------------------------------------- | ------- | -------------------------------------------- |
| `gitpod_runnerkit_supervisor_status_events_total` | Counter | Supervisor status events received |
| `gitpod_runnerkit_supervisor_watch_closes_total` | Counter | Supervisor watch connection closes by reason |
### Inverted RPC
These metrics track request delivery from the management plane to the runner over the runner's `WatchRequests` stream.
| Metric | Type | Description |
| ----------------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------- |
| `gitpod_runnerkit_inverted_rpc_requests_received_total` | Counter | Inverted RPC requests and events received by request type |
| `gitpod_runnerkit_inverted_rpc_requests_skipped_total` | Counter | Inverted RPC requests and events skipped before handler dispatch, by request type and reason |
| `gitpod_runnerkit_inverted_rpc_async_queue_depth` | Gauge | Current number of queued or running asynchronous inverted RPC requests |
| `gitpod_runnerkit_inverted_rpc_async_queue_capacity` | Gauge | Configured asynchronous inverted RPC queue capacity |
| `gitpod_runnerkit_inverted_rpc_async_queue_enqueues_total` | Counter | Asynchronous inverted RPC enqueue attempts by request type and outcome |
| `gitpod_runnerkit_inverted_rpc_async_queue_wait_duration_seconds` | Histogram | Time asynchronous inverted RPC requests spend waiting before handler execution starts |
| `gitpod_runnerkit_inverted_rpc_handler_duration_seconds` | Histogram | Runner-side inverted RPC handler duration by request type and result code |
| `gitpod_runnerkit_inverted_rpc_send_responses_total` | Counter | Attempts to send inverted RPC responses back to the management plane |
| `gitpod_runnerkit_inverted_rpc_watch_stream_connects_total` | Counter | `WatchRequests` stream connection attempts by delivery path and outcome |
| `gitpod_runnerkit_inverted_rpc_watch_stream_duration_seconds` | Histogram | `WatchRequests` stream session duration by delivery path and close reason |
`reason="not_owner"` is expected when broadcast delivery reaches a replica that does not own the resource. Treat this counter as diagnostic context, not as a failure signal; use the backend bridge completion metrics to determine the terminal caller outcome.
### Snapshots and warm pools
| Metric | Type | Description |
| -------------------------------------- | --------- | --------------------------------- |
| `snapshot_reconcile_duration_seconds` | Histogram | Snapshot processing time by phase |
| `snapshot_in_progress` | Gauge | Active snapshot operations |
| `snapshot_timeouts_total` | Counter | Snapshot timeouts |
| `warm_pool_reconcile_duration_seconds` | Histogram | Warm pool reconciliation duration |
| `warm_pool_deletions_total` | Counter | Warm pool instance deletions |
### Work queue health
| Metric | Type | Description |
| ---------------------------------- | --------- | --------------------------------- |
| `workqueue_depth` | Gauge | Current queue depth |
| `workqueue_queue_duration_seconds` | Histogram | Time items spend waiting in queue |
| `workqueue_work_duration_seconds` | Histogram | Time spent processing items |
| `workqueue_retries_total` | Counter | Processing retries |
### LLM proxy health
Scoped to proxy health only. **No token counts, no prompts, no usage patterns.** Ona can see whether the proxy is succeeding and how fast it responds, but nothing about what you send through it.
| Metric | Type | Description |
| ------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `gitpod_llm_proxy_requests_completed_total` | Counter | Final request outcome (`success`, `exhausted`, `rejected`, `stream_error`, `stream_failed`, `stream_incomplete`, or `incomplete_stream`) per endpoint and model |
| `gitpod_llm_requests_duration_seconds` | Histogram | End-to-end proxy request latency using the same outcome values |
| `gitpod_llm_errors_total` | Counter | Provider-side errors returned inside 200 responses, by error type |
| `gitpod_llm_failover_total` | Counter | Failovers between configured LLM providers |
Token usage metrics (`gitpod_llm_input_tokens_total`, `gitpod_llm_output_tokens_total`, cache counters, etc.) are **deliberately excluded** from the allowlist. They remain available to your own [custom metrics pipeline](/docs/ona/runners/monitoring-and-metrics) if you want them, but they are never forwarded to Ona.
### Agent and MCP
| Metric | Type | Description |
| ----------------- | ------- | --------------------------------------------------------- |
| `gitpod_mcp_*` | Various | MCP proxy request duration and count |
| `gitpod_memory_*` | Various | Redis memory usage, eviction cycles, and conversation age |
| `gitpod_skill_*` | Various | Skill API discovery metrics |
### Runner operations
| Metric | Type | Description |
| ------------------------- | ------- | ---------------------------------------------- |
| `gitpod_runner_manager_*` | Various | Runner manager operational metrics |
| `gitpod_runner_scm_*` | Various | SCM token refresh, cache invalidation, and TTL |
| `gitpod_runner_updater_*` | Various | Runner self-update duration and count |
| `gitpod_ip_allocator_*` | Various | IP address allocation metrics |
| `gitpod_kvstore_*` | Various | Key-value store operation metrics |
### Process health
| Metric | Type | Description |
| --------------------------- | ------- | ----------------------- |
| `go_goroutines` | Gauge | Current goroutine count |
| `go_memstats_alloc_bytes` | Gauge | Allocated heap memory |
| `process_cpu_seconds_total` | Counter | Total CPU time consumed |
### Cloud-specific metrics
| Metric | Type | Description |
| -------------------------------- | --------------- | ----------------------------------------------------------------------------- |
| `gitpod_ec2_runner_*` | Various | EC2 runner operational metrics |
| `gitpod_ecs_task_*` | Gauge / Counter | Task-level CPU, memory, and network usage from the ECS Task Metadata Endpoint |
| `gitpod_ecs_container_*` | Gauge / Counter | Per-container CPU, memory, and network usage within the runner task |
| `node_filesystem_*` | Gauge | Host filesystem capacity and availability metrics from node exporter |
| `node_disk_*` | Gauge / Counter | Host disk I/O metrics from node exporter |
| `environment_error_errors_total` | Counter | Environment errors by code and component |
| Metric | Type | Description |
| -------------------------------------------------- | --------- | --------------------------------------- |
| `gitpod_gcp_*` | Various | GCP runner operational metrics |
| `gitpod_gcp_compute_rate_limit_hits_total` | Counter | GCP API rate limit hits |
| `gitpod_gcp_compute_api_throttle_duration_seconds` | Histogram | Time spent throttled by GCP API |
| `gitpod_gcp_compute_circuit_breaker_state` | Gauge | Circuit breaker state for GCP API calls |
| `gitpod_gcp_runtime_reconciler_errors_total` | Counter | Runtime reconciler errors |
## How it works
1. The runner's Prometheus registry collects metrics every 15 seconds (this already happens for normal runner operation).
2. A managed metrics reporter filters the registry to the curated allowlist, encodes the result as a Prometheus remote write payload, and compresses it with Snappy.
3. The runner pushes the compressed payload to the Ona management plane every 60 seconds over the existing authenticated connection.
4. The management plane validates the payload, adds identifying labels (`organization_id`, `runner_id`, `runner_region`, `runner_type`), and forwards it to Ona's internal monitoring infrastructure.
Typical payloads are 5–15 KB compressed. The reporter runs independently of any self-managed metrics endpoint you may have configured.
## Auditing reported metrics
Every metrics payload the runner sends to Ona is also written to your cloud storage bucket, so you can audit exactly what data leaves your network.
Audit payloads are stored as Snappy-compressed Prometheus remote write protobufs at:
```
metrics/runner/{runner-id}/{YYYY}/{MM}/{DD}/{HHmmss}.pb.snappy
```
### Finding the bucket name
The bucket name is shown on your runner's settings page. When Ona managed metrics is enabled, the bucket URI appears below the toggle. Click the copy icon to copy it.
### Listing and downloading audit payloads
```bash theme={null}
aws s3 ls s3://YOUR_LOGS_BUCKET/metrics/runner/YOUR_RUNNER_ID/ --recursive
```
```bash theme={null}
# Download a specific payload
aws s3 cp s3://YOUR_LOGS_BUCKET/metrics/runner/YOUR_RUNNER_ID/2026/04/10/143000.pb.snappy ./payload.pb.snappy
```
```bash theme={null}
gcloud storage ls gs://YOUR_ASSETS_BUCKET/metrics/runner/YOUR_RUNNER_ID/ --recursive
```
```bash theme={null}
# Download a specific payload
gcloud storage cp gs://YOUR_ASSETS_BUCKET/metrics/runner/YOUR_RUNNER_ID/2026/04/10/143000.pb.snappy ./payload.pb.snappy
```
### Decoding audit payloads
Each `.pb.snappy` file is a Snappy-compressed [Prometheus remote write `WriteRequest`](https://prometheus.io/docs/concepts/remote_write_spec/) protobuf. You can decode it with standard Prometheus tooling or any protobuf decoder:
```bash theme={null}
# Using protoc (requires prometheus remote write proto definition)
cat payload.pb.snappy | python3 -c "
import sys, snappy
sys.stdout.buffer.write(snappy.decompress(sys.stdin.buffer.read()))
" | protoc --decode=prometheus.WriteRequest remote.proto
```
The decoded output shows every metric name, label set, and sample value: the exact data that was sent to Ona.
## Privacy and data handling
* **Opt-in only.** Disabled by default. You explicitly enable it per runner.
* **Push-based.** The runner pushes metrics to Ona. Ona never reaches into your runner or network.
* **Non-sensitive.** Only operational counters, gauges, and histograms. No user data, source code, environment variables, or secrets.
* **Non-interfering.** Independent of any self-managed metrics endpoint. Both can run simultaneously.
* **Auditable.** Every payload is persisted to your cloud storage for inspection.
* **Transparent.** The metric allowlist is hardcoded in the runner binary. Changes require a runner release and are documented on this page.
# Custom metrics pipeline
Source: https://ona.com/docs/ona/runners/monitoring-and-metrics
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.Looking for hands-off monitoring by Ona? See [Ona managed metrics](/docs/ona/runners/managed-metrics).
Ona runners expose Prometheus metrics for runner health, environment lifecycle, and resource utilization.
## Enabling metrics collection
1. Go to **Settings → Runners**
2. Select your runner
3. Toggle **Enable metrics collection**
4. Enter your configuration:
| Parameter | Required | Description |
| ------------------------- | -------- | -------------------------------- |
| **Metrics collector URL** | Yes | Prometheus remote write endpoint |
| **Username** | No | Basic auth username |
| **Password** | No | Basic auth password |
5. Click **Save Configuration**
Your credentials are encrypted at rest and transmitted securely. They are never exposed in logs or the dashboard.
Metrics flow immediately. Ensure outbound HTTPS (port 443) is allowed to your endpoint.
**Network requirements:** [AWS](/docs/ona/runners/aws/detailed-access-requirements#prometheus-remote-write) | [GCP](/docs/ona/runners/gcp/detailed-access-requirements#prometheus-remote-write)
## What to monitor
Runners expose many metrics, but not all require your attention. Some indicate issues you can resolve directly in your cloud account. Others signal problems that require Ona support. The rest provide visibility into usage and system health.
### Act on these
These metrics reflect infrastructure you control. Set up alerts and respond directly.
| Metric | What it means | What to do |
| ------------------------------------------ | --------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `up == 0` | Runner is unreachable | Check network connectivity, security groups, and firewall rules |
| `gitpod_gateway_proxy_up == 0` | Proxy is down | Check runner logs and network configuration |
| `gitpod_gateway_proxy_http_requests_total` | Proxy request errors | Filter for `status_code` 4xx/5xx to identify failing requests; may indicate misconfigured clients or network issues |
### Contact support for these
These metrics indicate issues within the runner itself. You can't resolve them directly, but they help you know when to reach out.
| Metric | What it means | What to tell support |
| ---------------------------------------- | ------------------------------------------ | --------------------------------------------------------------- |
| `gitpod_runnerkit_function_errors_total` | Total internal operation failures | Share the error rate trend and affected time window |
| `workqueue_unfinished_work_seconds` | Processing is stuck (value stays elevated) | Note how long it's been elevated and any correlated symptoms |
| `environment_error_errors_total` | Environment creation/operation failures | Include the `error_code` and `component` labels from the metric |
### Informational
These metrics provide visibility but don't typically require action.
| Metric | What it shows |
| ----------------------------------- | ---------------------------------- |
| `gitpod_runnerkit_active_instances` | Current environment count by state |
## Example alerts
These alerts cover high-signal scenarios that directly impact your users. Runner and proxy availability determine whether users can access environments at all. Proxy error rates indicate active failures during environment connections. These are the first things to know about when something goes wrong.
### Runner unreachable
Check your network configuration, security groups, and firewall rules.
```yaml theme={null}
- alert: RunnerUnreachable
expr: up == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Runner is unreachable"
runbook: "Check network connectivity and security groups"
```
### Proxy error rate elevated
Indicates users are experiencing failures connecting to environments.
```yaml theme={null}
- alert: ProxyErrorRateElevated
expr: |
sum(rate(gitpod_gateway_proxy_http_requests_total{status_code=~"5.."}[5m]))
/ sum(rate(gitpod_gateway_proxy_http_requests_total[5m])) > 0.05
for: 5m
labels:
severity: warning
annotations:
summary: "Proxy 5xx error rate above 5%"
runbook: "Check proxy logs and backend connectivity"
```
### High error rate (contact support)
This alert signals an issue you can't fix directly. Contact support with the time window and error details.
```yaml theme={null}
- alert: HighErrorRate
expr: |
rate(gitpod_runnerkit_function_errors_total[5m])
/ rate(gitpod_runnerkit_function_calls_total[5m]) > 0.1
for: 10m
labels:
severity: warning
annotations:
summary: "Runner error rate elevated"
runbook: "Contact Ona support with time window and error_code labels"
```
## Available metrics
All metrics include these common labels:
| Label | Description |
| ------------ | ------------------------------------------------------------- |
| `stack` | Runner stack name (e.g., `Ona-AWS-US-East---Enterprise`) |
| `account_id` | Cloud provider account ID |
| `region` | Deployment region |
| `instance` | Container hostname |
| `job` | Prometheus job name (`ec2_runner`, `runner_manager`, `proxy`) |
The tables below list additional metric-specific labels where applicable.
### Standard
Common metrics available on all runners.
| Metric | Type | Labels | Description |
| -------------------------------- | ----- | ----------------- | -------------------------------- |
| `up` | Gauge | - | Target health (1 = up, 0 = down) |
| `gitpod_gateway_proxy_up` | Gauge | - | Proxy health (1 = up, 0 = down) |
| `gitpod_ec2_runner_version_info` | Gauge | `version` | Runner version (AWS) |
| `gitpod_runner_version` | Gauge | `version`, `kind` | Runner version (GCP) |
### Environment (`gitpod_runnerkit_*`)
Metrics for environment lifecycle operations including creation, supervision, and state management.
| Metric | Type | Labels | Description |
| ------------------------------------------------------------ | --------- | ----------------------------------------------------- | ---------------------------------------------------- |
| `gitpod_runnerkit_active_instances` | Gauge | `state` | Environments by state |
| `gitpod_runnerkit_environment_operation_duration_seconds` | Histogram | `operation` | Operation duration |
| `gitpod_runnerkit_environment_start_retry_attempts_total` | Counter | `reason` (`capacity`) | Start fallback dispatches after a capacity rejection |
| `gitpod_runnerkit_environment_start_terminal_failures_total` | Counter | `reason` (`capacity_exhausted`, `provider`, `system`) | Start sessions that ended in failure |
| `gitpod_runnerkit_function_calls_total` | Counter | `function` | Function calls |
| `gitpod_runnerkit_function_duration_seconds` | Histogram | `function` | Function duration |
| `gitpod_runnerkit_function_errors_total` | Counter | `function` | Function errors |
| `gitpod_runnerkit_supervisor_status_events_total` | Counter | - | Supervisor events |
| `gitpod_runnerkit_supervisor_watch_starts_total` | Counter | - | Watch starts |
| `gitpod_runnerkit_supervisor_watch_closes_total` | Counter | `reason` | Watch closes |
| `gitpod_runnerkit_supervisor_watch_duration_seconds` | Histogram | - | Watch duration |
### Snapshots (`snapshot_*`)
Metrics for environment snapshot operations used for persistence and restore.
| Metric | Type | Labels | Description |
| ------------------------------------- | --------- | ----------------- | ------------------------ |
| `snapshot_reconcile_duration_seconds` | Histogram | `phase`, `result` | Processing time by phase |
| `snapshot_in_progress` | Gauge | `phase` | Active snapshots |
| `snapshot_timeouts_total` | Counter | - | Timeouts |
| `snapshot_deletions_total` | Counter | `result` | Deletions |
### Work queue (`workqueue_*`)
Internal task queue metrics. A growing `workqueue_depth` or high `workqueue_unfinished_work_seconds` may indicate the runner is falling behind on processing. Contact support if these remain elevated.
| Metric | Type | Labels | Description |
| --------------------------------------------- | --------- | ------ | -------------------- |
| `workqueue_depth` | Gauge | `name` | Queue depth |
| `workqueue_adds_total` | Counter | `name` | Items added |
| `workqueue_queue_duration_seconds` | Histogram | `name` | Time in queue |
| `workqueue_work_duration_seconds` | Histogram | `name` | Processing time |
| `workqueue_unfinished_work_seconds` | Gauge | `name` | Stuck work indicator |
| `workqueue_longest_running_processor_seconds` | Gauge | `name` | Longest processor |
| `workqueue_retries_total` | Counter | `name` | Retries |
### Errors (`environment_error_*`)
Tracks environment-level errors. Use the `error_code` and `component` labels when reporting issues to support.
| Metric | Type | Labels | Description |
| -------------------------------- | ------- | ---------------------------------------- | --------------------------------- |
| `environment_error_errors_total` | Counter | `instance_id`, `error_code`, `component` | Errors by instance/code/component |
### Runner proxy (`gitpod_gateway_proxy_*`)
The runner proxy handles all traffic between users and environments. It runs as a container named `proxy` in the same ECS task as the runner (AWS deployments).
#### HTTP requests
| Metric | Type | Labels | Description |
| ---------------------------------------------------- | --------- | ------------------------- | ----------------------------- |
| `gitpod_gateway_proxy_http_requests_total` | Counter | `protocol`, `status_code` | Total HTTP requests processed |
| `gitpod_gateway_proxy_http_request_duration_seconds` | Histogram | `protocol` | Request duration |
| `gitpod_gateway_proxy_http_requests_in_flight` | Gauge | `protocol` | Active requests |
| `gitpod_gateway_proxy_http_request_size_bytes` | Histogram | `protocol` | Request size |
| `gitpod_gateway_proxy_http_response_size_bytes` | Histogram | `protocol` | Response size |
#### Connections
| Metric | Type | Labels | Description |
| ------------------------------------------------------- | --------- | ------------------------ | ------------------- |
| `gitpod_gateway_proxy_http_connections_in_flight` | Gauge | `protocol` | Active connections |
| `gitpod_gateway_proxy_http_connection_errors_total` | Counter | `protocol`, `error_type` | Connection errors |
| `gitpod_gateway_proxy_http_connection_duration_seconds` | Histogram | `protocol` | Connection duration |
#### Backend
| Metric | Type | Labels | Description |
| ------------------------------------------------------------ | --------- | ------------ | -------------------------- |
| `gitpod_gateway_proxy_http_backend_request_duration_seconds` | Histogram | `protocol` | Backend request duration |
| `gitpod_gateway_proxy_http_backend_failures_total` | Counter | `error_type` | Backend failures |
| `gitpod_gateway_proxy_http_backend_connections_in_flight` | Gauge | `protocol` | Active backend connections |
#### DNS
| Metric | Type | Labels | Description |
| ----------------------------------------------------------------------- | --------- | ------------ | -------------------------------------- |
| `gitpod_gateway_proxy_dns_resolution_duration_seconds` | Histogram | - | DNS resolution time |
| `gitpod_gateway_proxy_dns_cache_hits_total` | Counter | - | DNS cache hits |
| `gitpod_gateway_proxy_dns_cache_misses_total` | Counter | - | DNS cache misses |
| `gitpod_gateway_proxy_dns_errors_total` | Counter | `error_type` | DNS errors |
| `gitpod_gateway_proxy_gitpod_proxy_dns_negative_cache_hits_total` | Counter | - | Negative cache hits |
| `gitpod_gateway_proxy_gitpod_proxy_dns_failures_by_code_total` | Counter | `code` | DNS failures by HTTP status |
| `gitpod_gateway_proxy_gitpod_proxy_dns_cache_invalidations_total` | Counter | - | Cache invalidations |
| `gitpod_gateway_proxy_gitpod_proxy_dns_cache_invalidations_batch_total` | Counter | - | Batch cache invalidations |
| `gitpod_gateway_proxy_gitpod_proxy_environment_not_found_total` | Counter | - | Requests for non-existent environments |
#### TLS
| Metric | Type | Labels | Description |
| ----------------------------------------------------- | --------- | ------------------ | ---------------------- |
| `gitpod_gateway_proxy_tls_handshake_duration_seconds` | Histogram | `protocol_version` | TLS handshake duration |
| `gitpod_gateway_proxy_tls_errors_total` | Counter | `error_type` | TLS errors |
#### Security
| Metric | Type | Labels | Description |
| ------------------------------------------------ | ------- | ------ | ---------------------------- |
| `gitpod_gateway_proxy_suspicious_requests_total` | Counter | `type` | Suspicious requests detected |
### Warm pools (`warm_pool_*`)
Metrics for [warm pool](/docs/ona/projects/warm-pools) scaling, instance lifecycle, and claim performance. All metrics include a `warm_pool_id` label.
| Metric | Type | Labels | Description |
| --------------------------------------- | --------- | ------------------------ | ----------------------------------------------------------- |
| `warm_pool_instances` | Gauge | `warm_pool_id` | Current number of running instances |
| `warm_pool_instances_by_state` | Gauge | `warm_pool_id`, `state` | Instance count by lifecycle state (`in_service`, `stopped`) |
| `warm_pool_target_size` | Gauge | `warm_pool_id` | Current desired instance count (set by the scaling policy) |
| `warm_pool_min_size` | Gauge | `warm_pool_id` | Configured minimum pool size |
| `warm_pool_max_size` | Gauge | `warm_pool_id` | Configured maximum pool size |
| `warm_pool_claims_total` | Counter | `warm_pool_id`, `result` | Claim attempts (`success`, `instance_not_found`, `error`) |
| `warm_pool_claim_instance_age_seconds` | Histogram | `warm_pool_id` | Age of instances at claim time (time since launch) |
| `warm_pool_oldest_instance_age_seconds` | Gauge | `warm_pool_id` | Age of the oldest running instance |
| `warm_pool_instances_created_total` | Counter | `warm_pool_id` | Total instances launched |
| `warm_pool_instances_terminated_total` | Counter | `warm_pool_id` | Total instances terminated |
| `warm_pool_reconcile_duration_seconds` | Histogram | `phase`, `result` | Reconciliation duration by pool phase |
**Key metrics to watch:**
* **`warm_pool_claims_total` with `result="instance_not_found"`**: Indicates users hit a cold start because no warm instance was available. If this happens frequently, increase `max-size` or `min-size` (the pool may be scaling down too aggressively).
* **`warm_pool_claim_instance_age_seconds`**: Shows how long instances waited before being claimed. Very short ages may indicate the pool is too small for demand.
* **`warm_pool_instances_by_state`**: Compare `in_service` vs `stopped` counts to verify the pool is scaling as expected.
### AWS-specific (`gitpod_ec2_runner_*`, `gitpod_ecs_*`)
Metrics specific to AWS runner deployments. The `gitpod_ecs_*` series are sourced from the ECS Task Metadata Endpoint and report task- and container-level resource usage. They are emitted on every ECS launch type (EC2 and Fargate) and can be used to detect a hot or memory-pressured runner task before the symptoms surface elsewhere.
| Metric | Type | Labels | Description |
| --------------------------------------------- | ------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| `gitpod_ecs_task_cpu_utilized_percent` | Gauge | `service`, `task_family` | Task CPU utilization, summed across all containers in the task |
| `gitpod_ecs_task_memory_utilized_bytes` | Gauge | `service`, `task_family` | Task memory used in bytes, summed across all containers |
| `gitpod_ecs_task_memory_limit_bytes` | Gauge | `service`, `task_family` | Task memory limit (only emitted when the task definition sets a task-level memory limit) |
| `gitpod_ecs_task_network_rx_bytes_total` | Counter | `service`, `task_family` | Bytes received on the task's network interfaces |
| `gitpod_ecs_task_network_tx_bytes_total` | Counter | `service`, `task_family` | Bytes transmitted on the task's network interfaces |
| `gitpod_ecs_container_cpu_utilized_percent` | Gauge | `service`, `task_family`, `container_name`, `container_type` | Per-container CPU utilization |
| `gitpod_ecs_container_memory_utilized_bytes` | Gauge | `service`, `task_family`, `container_name`, `container_type` | Per-container memory used |
| `gitpod_ecs_container_network_rx_bytes_total` | Counter | `service`, `task_family`, `container_name`, `container_type` | Per-container bytes received |
| `gitpod_ecs_container_network_tx_bytes_total` | Counter | `service`, `task_family`, `container_name`, `container_type` | Per-container bytes transmitted |
### GCP-specific (`gitpod_gcp_*`)
Metrics specific to GCP runner deployments, tracking compute and Redis connectivity.
| Metric | Type | Labels | Description |
| -------------------------------------------------- | ------- | ------------ | -------------- |
| `gitpod_gcp_compute_network_errors_total` | Counter | `error_type` | Network errors |
| `gitpod_gcp_compute_redis_connection_errors_total` | Counter | - | Redis errors |
| `gitpod_gcp_compute_redis_connection_health` | Gauge | - | Redis health |
| `gitpod_gcp_network_connection_health` | Gauge | - | Network health |
## GCP Runner alerts and dashboards
If you are using a GCP Runner, pre-built Grafana alerts and a dashboard are available that you can import directly. See [Alerts and Dashboards](/docs/ona/runners/gcp/alerts-and-dashboards) for details.
## Troubleshooting
1. Check network connectivity to your endpoint
2. Verify authentication credentials
3. Check runner logs for errors
**Network requirements:** [AWS](/docs/ona/runners/aws/detailed-access-requirements#prometheus-remote-write) | [GCP](/docs/ona/runners/gcp/detailed-access-requirements#prometheus-remote-write)
* Aggregate at runner level instead of per-environment
* Adjust retention for high-volume metrics
# Ona Cloud
Source: https://ona.com/docs/ona/runners/ona-cloud
Ona Cloud is managed infrastructure for Core tier users. No setup required - a runner in your nearest region is automatically added when you create your account.
## Regions
| Region | Location |
| ------ | ------------------------ |
| Europe | eu-central-1 (Frankfurt) |
| USA | us-east-1 (N. Virginia) |
Enable additional regions in **Settings → Runners**.
## Creating environments
Select your preferred region when creating an environment:
## Managing runners
Delete unused regional runners via the kebab menu. Environments on that runner will be stopped and deleted. You can re-enable the region later if needed.
## Restricting access to admins only
To prevent regular members from using Ona Cloud runners (e.g. in Enterprise orgs that use self-hosted runners exclusively):
1. Go to [Settings > Runners](https://app.ona.com/settings/runners)
2. Click on the Ona Cloud runner (e.g. `Ona Cloud (US01)`)
3. In the **Sharing** section at the bottom, select **Only organization admins**
4. Repeat for each Ona Cloud runner
This also hides the Git connection buttons for those runners at [Settings > Git Authentications](https://app.ona.com/settings/git-authentications).
## Removing Ona Cloud runners (Enterprise)
Enterprise organizations may see Ona Cloud runners that aren't needed. These are hidden from the Runners settings page but can appear elsewhere (e.g. Git Authentications). Remove them via CLI:
```bash theme={null}
ona runner list # find the Ona Cloud runner IDs
ona runner delete # delete each one
```
## Billing
* [Billing overview](/docs/ona/billing/overview)
* [Cost & Budgets](/docs/ona/billing/usage)
## Upgrading to Enterprise
For single-tenant infrastructure in your VPC, [contact sales](https://ona.com/contact/sales). Enterprise includes:
* Deploy in your AWS or GCP account
* Private networking and internal resource access
* Self-hosted Git providers (GitHub Enterprise, GitLab, Azure DevOps, Bitbucket)
* Custom regions and environment classes
* Priority support
See [Runners overview](/docs/ona/runners/overview) for details.
# Runner infrastructure
Source: https://ona.com/docs/ona/runners/overview
Runners provision and manage your environments and agents. Deploy on Ona Cloud or in your own AWS or GCP account.
Runners are the infrastructure layer that provisions and manages your [environments](/docs/ona/environments/overview) and [agents](/docs/ona/agents/codex). Every environment you launch and every agent task you run executes on a runner.
## What a runner handles
A runner handles everything that touches your code:
* **Environment provisioning:** creates isolated VMs from your [Dev Container](/docs/ona/configuration/devcontainer/overview) configuration
* **Source code access:** clones repositories using credentials stored on the runner, not the management plane
* **Secret injection:** delivers [secrets](/docs/ona/configuration/secrets/overview) into environments at startup
* **Agent execution:** runs [Codex Agent](/docs/ona/agents/codex) tasks inside the same isolated environments developers use
* **Build and test execution:** runs [prebuilds](/docs/ona/projects/prebuilds), [tasks, and services](/docs/ona/configuration/tasks-and-services/overview) defined in your project
## How runners fit into the architecture
Ona uses a two-plane architecture:
| | Management Plane | Runners |
| --------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------ |
| **Hosted by** | Ona | Ona Cloud or your VPC |
| **Handles** | Authentication, org settings, guardrails, coordination | Environment provisioning, code access, secret injection, agent execution |
| **Touches your code** | No | Yes |
The management plane coordinates. Runners execute. This separation exists for three reasons:
1. **Data sovereignty.** Source code and SCM credentials stay on runners, not the management plane. With a runner in your VPC, sensitive assets never leave your infrastructure.
2. **Compliance.** [Guardrails](/docs/ona/guardrails/overview) are defined on the management plane and enforced at the runner level. [Audit logs](/docs/ona/audit-logs/overview) track every action.
3. **Multi-region, multi-cloud.** Deploy runners in different regions and cloud providers. Each runner supports multiple environment classes with different compute specs.
For a deeper look at data flow between planes, see the [Architecture overview](/docs/ona/understanding/architecture).
## Deployment options
### Ona Cloud
Zero-setup managed infrastructure. A runner in your nearest region is automatically provisioned when you create your account.
* No infrastructure to manage
* Available in **EU (Frankfurt)** and **US (N. Virginia)**
* Included with Core plans
Best for individuals, small teams, and organizations that want to start immediately.
[Get started with Ona Cloud →](/docs/ona/runners/ona-cloud)
### AWS
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Deploy runners as ECS services in your own AWS VPC. Environments run as EC2 instances. Deployment is automated via CloudFormation templates.
* Private networking with AWS PrivateLink
* Custom domains with your own SSL/TLS certificates
* Fine-grained IAM permission boundaries
* HTTP proxy and custom CA support
Setup takes 30-60 minutes. See [AWS Runner overview](/docs/ona/runners/aws/overview) and [Setup guide](/docs/ona/runners/aws/setup).
### GCP
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Deploy runners in your Google Cloud VPC. Environments run as Compute Engine instances. Deployment is automated via Terraform modules.
* External or internal load balancer configurations
* Private Google Artifact Registry access
* Full control over networking and security
Setup takes 30-60 minutes. See [GCP Runner overview](/docs/ona/runners/gcp/overview) and [Setup guide](/docs/ona/runners/gcp/setup).
## Choosing a deployment option
| | Ona Cloud | AWS / GCP (your VPC) |
| ------------------- | ---------------------------- | ------------------------------------ |
| **Setup time** | Instant | 30-60 minutes |
| **Infrastructure** | Managed by Ona | Managed by you |
| **Data residency** | Ona's infrastructure | Your VPC |
| **Network control** | Standard | Full (PrivateLink, internal LB, VPN) |
| **Compliance** | SOC 2 | Your controls + Ona guardrails |
| **Best for** | Getting started, small teams | Enterprise, regulated industries |
Organizations can run multiple runners across regions and cloud providers to support distributed teams and compliance requirements.
## Capabilities across all deployment options
All runners support these features regardless of where they run:
* [Prebuilds](/docs/ona/projects/prebuilds) for fast environment startup
* [Codex Agent](/docs/ona/agents/codex) for agent-driven development
* Environment classes with configurable compute (CPU, memory, storage)
* [Dual disk environments](/docs/ona/runners/dual-disk) for resilient Enterprise environment storage
* Dev Container caching for faster rebuilds
* [Custom metrics pipeline](/docs/ona/runners/monitoring-and-metrics) for operational visibility
* Runner sharing across organizations
## Next steps
* [Ona Cloud](/docs/ona/runners/ona-cloud): get started with zero setup
* [AWS Setup](/docs/ona/runners/aws/setup): deploy a runner in your AWS account
* [GCP Setup](/docs/ona/runners/gcp/setup): deploy a runner in your GCP project
* [Architecture overview](/docs/ona/understanding/architecture): how the management plane and runners interact
* [Capacity planning](/docs/ona/runners/aws/capacity-planning): plan infrastructure requirements for runners in your VPC
# Automated updates
Source: https://ona.com/docs/ona/runners/runner-updates
How runners are updated automatically and how to configure update windows.
Runners include a built-in update mechanism that automatically applies new features, improvements, and security patches. This page covers how automatic updates work and how to configure update windows. For cloud-specific infrastructure upgrades, see the [GCP](/docs/ona/runners/gcp/update-runner) or [AWS](/docs/ona/runners/aws/update-runner) update guides.
## Automatic updates
The runner periodically checks the Ona API for new versions. When a newer version is available and the infrastructure is compatible, the runner updates itself automatically.
* Updates are non-disruptive to running environments
* Failed updates automatically roll back without impacting existing functionality
* The runner maintains its configuration and credentials through updates
* View the current version at **Settings → Runners**
Automatic updates cover application-level changes. Infrastructure changes (Terraform modules, CloudFormation templates) require manual upgrades. See your provider's update guide.
## Update window
By default, automatic updates can occur at any time. You can restrict updates to a specific daily time window (UTC) to align with your maintenance schedule.
1. Navigate to **Settings → Runners** and select your runner
2. Scroll to **Runner Configuration**
3. Enable **Set update window**
4. Select a **Start hour** and **End hour** (UTC). The window must be at least 2 hours long. Overnight windows are supported (e.g., 22:00 to 04:00 UTC).
5. Click **Save Configuration**
To remove the restriction and allow updates at any time, disable the **Set update window** toggle. When the toggle is off, the runner applies updates as soon as they are available.
The update window controls when routine automatic updates are applied. It does not affect manual infrastructure upgrades.
In rare cases, Ona may push a **hotfix release** that bypasses the update window. Hotfixes are reserved for fixes to functional degradation of the runner or critical security patches. You will be notified before a hotfix is applied.
# SCIM Provisioning
Source: https://ona.com/docs/ona/scim/overview
Available on the Enterprise plan. Currently in **beta**. [Contact sales](https://ona.com/contact/sales) to learn more.
SCIM (System for Cross-domain Identity Management) lets your identity provider automatically create, update, and deactivate user accounts in Ona. Instead of manually inviting users or removing access, your IdP pushes changes to Ona as they happen in your directory.
## How it works
When SCIM is configured, your identity provider communicates with Ona through a SCIM endpoint using a bearer token for authentication. Changes in your IdP directory — such as adding a new employee or disabling an account — are automatically reflected in your Ona organization.
SCIM provisioning is linked to an existing [SSO login provider](/docs/ona/sso/overview). The linked SSO configuration determines how provisioned users authenticate when signing in to Ona.
## Prerequisites
* An active [SSO login provider](/docs/ona/sso/overview) configured in your organization
* Admin-level access to your organization settings in Ona
* Admin access to your identity provider (e.g., Microsoft Entra ID)
## Setting up SCIM in Ona
### Step 1. Open SCIM configuration
Navigate to **Organization Settings > Login and Security**. Scroll to the **SCIM Provisioning** section.
*SCIM Provisioning — initial state*
Click **Setup now** to begin.
### Step 2. Create a SCIM configuration
In the configuration dialog:
1. Select the **Linked SSO configuration** — this is the SSO provider that provisioned users will use to sign in
2. Enter a **Name** for this SCIM configuration
3. Click **Create**
*New SCIM configuration — select SSO provider and name*
After creation, Ona displays the **SCIM endpoint URL** and a **bearer token**.
Copy the bearer token immediately. It is shown only once and cannot be retrieved later.
You will need both the endpoint URL and the token to configure your identity provider in the next step.
## Configuring your identity provider
### Microsoft Entra ID
#### Creating an Enterprise Application
If you don't already have an Enterprise Application for Ona, create one:
1. Open the [Microsoft Entra admin center](https://entra.microsoft.com/)
2. Navigate to **Enterprise Applications**
3. Click **New application**, then select **Create your own application**
4. Enter a name for the application (e.g., `Ona`)
5. Select **Integrate any other application you don't find in the gallery (Non-gallery)**
6. Click **Create**
*Microsoft Entra — create a non-gallery enterprise application*
#### Configuring provisioning
1. In the [Microsoft Entra admin center](https://entra.microsoft.com/), navigate to **Enterprise Applications** and select the application you created for Ona
2. Go to **Provisioning** and select **Provisioning** again
3. Set **Provisioning Mode** to **Automatic**
4. Under **Admin Credentials**, configure the following:
* **Authentication Method**: Bearer Authentication
* **Tenant URL**: Paste the SCIM endpoint URL from Ona
* **Secret Token**: Paste the bearer token from Ona
5. Click **Test Connection** to verify the configuration
Once the test succeeds, save the configuration and enable provisioning.
### Scoping users
We recommend provisioning only the users who will use Ona, rather than your entire directory. You can control this with scoping filters in your identity provider.
In Microsoft Entra:
1. In the **Provisioning** tab, select **Mappings**
2. Open the mapping for **Users** or **Groups**
3. Under **Source Object Scope**, add a **Scoping Filter Group** to limit which users are provisioned
For details on building scoping filters, see [Microsoft's scoping filter documentation](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/define-conditional-rules-for-provisioning-user-accounts?pivots=app-provisioning).
## Restricting account creation to SCIM
Once SCIM is configured and enabled, you can require that all organization access goes through SCIM by enabling the [Restrict account creation to SCIM](/docs/ona/organizations/policies/scim-account-restriction) policy. When enabled, users who can authenticate via SSO but are not provisioned through SCIM are blocked from joining the organization.
This is useful when you want your identity provider to be the single source of truth for who has access to Ona.
# Amazon Cognito
Source: https://ona.com/docs/ona/sso/cognito
You can set up Single Sign-on (SSO) with Amazon Cognito for your team.
This section helps you to create an OIDC application with Amazon Cognito. The *Client ID*, *Client Secret*, and *Issuer URL* of this OIDC application are required to setup SSO in Ona. See the [step-by-step guide](/docs/ona/sso/overview#setting-up-single-sign-on) for the general instructions.
## Prerequisites
As prerequisites you will need the following:
* Access to set up a new [Amazon Cognito application](https://console.aws.amazon.com/cognito/home) in your AWS account.
## Create an OIDC application
1. Navigate to [Amazon Cognito](https://console.aws.amazon.com/cognito/home) service page, then select `Set up your application`.
2. Configure the application by filling out the form:
* **Application type**: `Traditional web application`
* **Name**: `Ona`
* **Options for sign-in identifiers**:
* `Email`
* **Required attributes for sign-up**:
* `email`
* `name`
* **Return URL**: `https://app.gitpod.io/auth/oidc/callback`
Click the *Create* button.
3. Obtain *Client ID*, *Client Secret* from the Overview page
Upon creation of the application, you will be redirected to the then created user pool. Learn more about [Amazon Cognito user pools](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools.html?icmpid=docs_cognito_console_help_panel).
* Feel free to rename the user pool before proceeding!
* Obtain **Issuer URL**
* You'll find the **User pool ID** here
* The pattern for the *Issuer URL* is:
`https://cognito-idp..amazonaws.com/`
* Verify to use the correct URL by opening the OIDC Discovery location `/.well-known/openid-configuration` in your browser, i.e. open `https://cognito-idp..amazonaws.com/