# Ona Changelog
Source: https://ona.com/docs/changelog
Product updates and announcements
## 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 inactivity 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.
* 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.
## Older updates
## 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)
## Announcement Banner
Organization admins can now display announcement banners to communicate important information to all organization members directly within the dashboard.
**What's new:**
* **Admin settings page**: Configure banners from Settings → Organization → Announcements
* **Markdown support**: Format messages with bold, italic, and links
* **Live preview**: See exactly how your banner will appear before publishing
* **Toggle control**: Quickly enable or disable the banner without losing your message
**Getting started:**
1. Navigate to **Settings → Organization → Announcements**
2. Enable the announcement banner 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 announcement banners](/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 get more powerful with 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
* **Seamless integration**: Agents work natively 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. Please note that the removal of 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, migration is seamless; Ona will automatically load 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
* **Seamless integration** - 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 the powerful 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, a powerful 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 environment 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.
* Empower developers to 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). Ona Agent can now use this 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 Ona Agent 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`)
```
Ona Agent automatically loads 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
Use Codex as a separate agent in Ona Cloud environments.
Available on the Core plan. Codex Agent is currently supported on Ona Cloud only. [Contact sales](https://ona.com/contact/sales) to learn more.
Codex Agent lets you use Codex in an Ona Cloud environment. It is separate from Ona Agent, but it runs with the same 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.
By default, Codex Agent uses the model access available to your organization. If you connect your ChatGPT account, Codex Agent uses your ChatGPT plan for model requests instead.
## Prerequisites
* Your organization is on the Core plan.
* Your organization uses Ona Cloud.
* Codex Agent is enabled for your organization.
To use your ChatGPT plan for Codex model requests, you 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.
## Billing
The environment still consumes OCUs while Codex Agent runs. See [Cost & Budgets](/docs/ona/billing/usage).
If you connect your ChatGPT account, OpenAI manages ChatGPT plan usage and limits for Codex model requests. Ona does not charge OCUs for Codex model requests that use your connected ChatGPT account.
## Related setup
* [Connect Codex to ChatGPT](/docs/ona/integrations/configure-codex): use your ChatGPT plan for Codex model requests
* [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 your Ona Agent prompts for visual context.
Attach PNG or JPEG images to your prompts so Ona Agent can see what you see. 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.
# Mermaid diagrams
Source: https://ona.com/docs/ona/agents/mermaid-diagrams
Visualize architecture, dependencies, and workflows with agent-generated diagrams
Ona Agent 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
Source: https://ona.com/docs/ona/agents/overview
Ona Agent completes engineering tasks autonomously in secure, isolated environments.
Ona Agent completes engineering tasks autonomously in secure, isolated environments. It writes code, runs tests, and opens pull requests while respecting your organization's security policies and guardrails.
**Ona Agent works out of the box with zero configuration.** Start a session, give it a task, and it gets to work. As you use it more, you can teach it your codebase conventions, create custom skills, and configure guardrails.
Ona also supports [Codex Agent](/docs/ona/agents/codex), a separate agent that runs in Ona environments with the same project context, integrations, and guardrails.
## 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 it 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
None required to get started. Ona Agent works immediately with [Ona Cloud](/docs/ona/runners/ona-cloud).
For advanced setups:
* **Your own infrastructure**: deploy runners in [AWS](/docs/ona/runners/aws/overview) or [GCP](/docs/ona/runners/gcp/overview)
* **Faster startup**: configure a [Dev Container](/docs/ona/configuration/devcontainer/getting-started) for your repository
## Get productive
* **Teach agents your codebase**: create an [AGENTS.md](/docs/ona/agents-md) with your conventions, or add [Skills](/docs/ona/agents-md#skills-for-repository-specific-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
* [AGENTS.md](/docs/ona/agents-md): teach agents your conventions
* [Codex Agent](/docs/ona/agents/codex): use Codex as a separate agent in Ona
* [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
Ona Agent includes built-in tools for GitHub, GitLab, and Bitbucket Cloud. Agents 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 Ona Agent to follow your workflows automatically.
Skills are `SKILL.md` files containing step-by-step workflow instructions. They teach Ona Agent 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 Ona 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 Ona Agent discovers skills
At session start, Ona 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 Ona 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 Ona 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 Ona 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 Ona 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
# API Reference
Source: https://ona.com/docs/ona/api-reference
# 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 |
## 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.
## Save and edit
Click **Save** to create the Automation. All settings can be modified after creation.
Pull request triggers require an event source: the [GitHub App](/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).
## Concurrency 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 plans are unrestricted by tiering but are subject to the current system-wide ceiling of 25 concurrent and 100 total actions per Automation. [Contact sales](https://ona.com/contact/sales) if you need higher limits.
Setting values above your plan's cap returns an error. Existing Automations are not retroactively affected. Only new creates and updates are validated.
### 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 `automations.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).
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 `automations.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.
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 |
| Webhooks (PR triggers) | - | |
| 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
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. Non-enterprise organizations can use manual and time-based triggers.
## 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**.
3. Confirm target repositories/projects.
## 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.
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**
The Automation creates actions for the selected targets, which you can then monitor from the execution view.
## 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
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
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**, **GitLab**, and **Bitbucket Cloud**. 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 App](/docs/ona/integrations/configure-github)** | You use GitHub.com and have the [Ona GitHub App](/docs/ona/integrations/configure-github) installed. No extra setup — Ona receives PR events through the App. |
| **[Webhook](/docs/ona/automations/webhooks)** | You use GitLab or Bitbucket Cloud, or you prefer not to install the GitHub App. You create a webhook in Ona and register it in your Git provider. |
#### GitHub App
If your organization has the [Ona GitHub App](/docs/ona/integrations/configure-github) installed, select **GitHub App** as the event source. Ona receives PR events directly through the App.
#### 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 App](/docs/ona/integrations/configure-github): install the Ona GitHub App 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 Automations page
* Verify organization has Automations enabled.
* If not admin, confirm you are in a group with shared Automation access.
### "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 Ona 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/automations.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.
### 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 Ona 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 automation tasks.
Add a task to your `automations.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 Ona 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 Ona Agent sees these tasks available, 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 automations update -
```
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 automations update -
```
**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 " + ., "command": "cd " + . + " && go run ."}}' |
jq -s 'add | {"services": .}' |
ona automations update -
```
**Load configuration from a remote source:**
```bash theme={null}
curl https://example.com/automations.json | ona automations update -
```
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 automations task start build-and-test --environment-id $ENV_ID)
# Stream logs
ona automations task logs $TASK_ID --environment-id $ENV_ID
# Check result and clean up
TASK_STATUS=$(ona automations 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
**Services** are long-running processes that stay active throughout your session:
* Databases (PostgreSQL, MySQL)
* Backend and frontend servers
* Caching systems (Redis)
**Tasks** are one-off actions that run and complete:
* Installing dependencies
* Running tests
* Seeding databases
* Authenticating with cloud providers
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.
## Quick example
```yaml theme={null}
# .ona/automations.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
dependsOn:
- database
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 is ready
3. Seeds the database with test data
4. Makes "Run tests" available as a manual action
## 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. |
| `beforeSnapshot` | ✗ | ✓ | Before an environment snapshot is created |
See [automations.yaml schema](/docs/ona/reference/automations-yaml-schema#triggers) for complete trigger documentation, including [how triggers interact with prebuilds](/docs/ona/reference/automations-yaml-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
* [automations.yaml schema](/docs/ona/reference/automations-yaml-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.
### automations.yaml
Defines startup tasks (install dependencies, seed databases) and long-running services (databases, servers). Place it at `.devcontainer/automations.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 `automations.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 automations, 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 automations (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 automation services exist for every service required or recommended to run any app in this environment.
- Ona automation services exist for every app, for the standard or documented configurations.
- Ona automation 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 automation 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 automation tasks start and finish successfully.
- Ona automation 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.
* **`automations.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 `automations.yaml` at the repository root. To use a different path (e.g. `.ona/automations.yaml`), set the **Automations file 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) (environment details, 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) (environment details, 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 [environment 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. Archived environments move to a separate view and can be unarchived or deleted. You receive an email when environments are archived.
## Viewing archived environments
Select **Archived** from the sidebar toggle to view archived environments. Switch back to **Project** or **Recently active** to return to the main view.
## Managing archived environments
Hover over an archived environment to reveal actions:
* **Unarchive** - click the restore icon. The environment returns to your main list.
* **Delete** - click the trash icon and confirm in the dialog.
Deleting an environment permanently removes all content. This cannot be undone.
### Delete all
Click **Delete All** at the bottom and confirm to remove all archived environments.
## 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 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 override user preferences when more restrictive. Disabled options in the dropdown indicate policy 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.
No, only stopped environments.
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.
* **[Agents](/docs/ona/agents/overview)**: work 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: `jq`, `openssl`, `curl`
If SLSA verification fails, the installation aborts with an error. There is no fallback to unverified download - this ensures you're always notified of potential tampering.
**Manual [SLSA](https://slsa.dev) verification**
SLSA verification cryptographically proves the CLI was built by the official build system.
The verification script checks:
* Artifact SHA256 matches the attestation subject digest
* Provenance metadata confirms the build came from `gitpod-io/gitpod-next`
* Certificate was issued by Sigstore
* Entry exists in the Rekor transparency log
* DSSE envelope structure is valid
Requirements: `jq`, `openssl`, `curl`
```bash theme={null}
# Get manifest and extract packageHash for your platform
PLATFORM="linux-amd64" # or darwin-amd64, darwin-arm64, windows-amd64
MANIFEST=$(curl -sL https://app.gitpod.io/releases/cli/stable/manifest.json)
VERSION=$(echo "$MANIFEST" | jq -r '.version')
HASH=$(echo "$MANIFEST" | jq -r ".downloads[\"$PLATFORM\"].packageHash")
# Download tarball and attestation
BASE_URL="https://app.gitpod.io/releases/cli/releases/$VERSION"
curl -fsSL -O "$BASE_URL/$HASH.tar.gz"
curl -fsSL -O "$BASE_URL/$HASH.tar.gz.att"
# Download and run verification script
curl -fsSL -O https://app.gitpod.io/releases/cli/verify-slsa.sh
chmod +x verify-slsa.sh
./verify-slsa.sh "$HASH.tar.gz"
# Extract and install
tar -xzf "$HASH.tar.gz" ./ona-cli
chmod +x ona-cli
sudo mv ona-cli /usr/local/bin/ona
```
**Option 2: 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 automations`, `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 automations service list
ona environment port open 3000
# After running ona login, these still work without --environment-id
ona login
ona automations 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.
## 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 automations 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 [environment 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.
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 automations init
ona automations update automations.yaml
ona automations task list
ona automations task start
ona automations task logs
ona automations service list
ona automations 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**, 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.
## 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 you disconnect the integration, future Codex sessions 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).
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.
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 App
Source: https://ona.com/docs/ona/integrations/configure-github
Install the Ona GitHub App on your GitHub organization.
Available on the Core plan. [Contact sales](https://ona.com/contact/sales) to enable it for Enterprise.
This page is for the organization admin who installs the Ona GitHub App. For end-user usage, see [Mention Ona on a pull request](/docs/ona/integrations/github-pr-mentions).
The GitHub App is a separate integration from [GitHub source control](/docs/ona/source-control/github), which configures repository access for environments.
## Prerequisites
* You are an admin of an Ona organization.
* Your organization is on the Core plan. The integration is not enabled on Enterprise by default; [contact sales](https://ona.com/contact/sales) to turn it on for your organization.
* You have admin rights on the GitHub organization (or personal account) where the App will be installed.
## Install the Ona GitHub App
1. In Ona, go to **Organization Settings** > **Integrations**.
2. Find **GitHub App** and click **Install**.
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 installation status on the integration page.
## 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 the App
Disable the integration if you want to stop Ona from responding to PR mentions without uninstalling the App on GitHub (for example, during a migration or incident).
1. In Ona, go to **Organization Settings** > **Integrations**.
2. Find **GitHub App** and toggle the switch off.
While disabled:
* The App stays installed on GitHub and keeps receiving webhook events, but Ona ignores them. No new agent sessions start for `@ona-agent` mentions.
To resume, toggle the 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 the App is installed.
* [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.
## 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.
# 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 Ona 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 Ona agent on that PR. The agent reads the PR diff and recent comments, then works on the task you describe.
For installation, see [GitHub App](/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 [Ona GitHub App](/docs/ona/integrations/configure-github) is installed on 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 App](/docs/ona/integrations/configure-github): install and manage the App.
* [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 [Ona GitHub App](/docs/ona/integrations/configure-github) installed on 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 App install. 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.
* **Per-user MCP authentication** happens after the org integration is enabled. Each user authenticates the integration with their own account so the agent acts with their permissions, not a shared service account.
In short:
1. **Organization-level enablement** by an administrator
2. **User authentication** so the agent acts with your permissions
Available integrations:
| Integration | What agents can do | Setup |
| ----------- | ------------------------------------------------------------------ | ------------------------------------------------------------ |
| Linear | Read issues, update status, use backlog context | [Configure Linear](/docs/ona/integrations/configure-linear) |
| 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 App | Mention `@ona-agent` on a pull request to start an agent on the PR | [GitHub App](/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 from the CLI
Use `--admission` to control who can access the port. If you omit it, the default is `everyone`. For admission level definitions, see [Port access levels](/docs/ona/organizations/policies/port-sharing#port-access-levels).
```bash theme={null}
# Open a port only you can access
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
# Allow 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
```
## 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 public URL with TLS, visible in dashboard | Shareable URLs, browser IDE previews, CI integrations |
## Opening a port and previewing in the browser
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
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
The Ona SDK lets you create environments, run tasks, manage automations, and control runners programmatically. Available in Python, Node/TypeScript, and Go.
## SDKs available
* **[Python SDK](https://pypi.org/project/gitpod-sdk/)**
* **[Node/TypeScript SDK](https://www.npmjs.com/package/@gitpod/sdk)**
* **[Go SDK](https://github.com/gitpod-io/gitpod-sdk-go)**
See the [API Reference](https://ona.com/docs/api-reference) for full details.
## Getting started
### 1. Sign up
Go to [app.ona.com](https://app.ona.com) and sign up. Then generate a [personal access token](/docs/ona/integrations/personal-access-token) for SDK authentication.
### 2. Install the SDK
```bash theme={null}
# Python
pip install gitpod-sdk
# Node/TypeScript
npm install @gitpod/sdk
# Go
go get github.com/gitpod-io/gitpod-sdk-go
```
### 3. Authenticate
Set the `GITPOD_API_KEY` environment variable with your [personal access token](/docs/ona/integrations/personal-access-token):
```bash theme={null}
export GITPOD_API_KEY="your_token_here"
```
The SDK packages still use the `gitpod` naming convention (e.g. `GITPOD_API_KEY`, `from gitpod import Gitpod`). This will be updated in a future release.
Or pass the token directly in code:
```python theme={null}
# Python
from gitpod import Gitpod
gitpod = Gitpod(bearer_token="your_token_here")
```
```go theme={null}
// Go
import (
"github.com/gitpod-io/gitpod-sdk-go"
"github.com/gitpod-io/gitpod-sdk-go/option"
)
client := gitpod.NewClient(option.WithBearerToken("your_token_here"))
```
```typescript theme={null}
// TypeScript
import { Gitpod } from '@gitpod/sdk';
const gitpod = new Gitpod({ bearerToken: 'your_token_here' });
```
### 4. Run an example
Create an environment and run a command with the Python SDK:
```python theme={null}
import asyncio
from gitpod import AsyncGitpod
import gitpod.lib as util
repo_url = "https://github.com/containerd/containerd"
command_to_execute = "go test -v -short ./..."
async def execute_command_in_environment():
client = AsyncGitpod()
machine_class_id = (await util.find_most_used_environment_class(client)).id
create_params = {
"desired_phase": "ENVIRONMENT_PHASE_RUNNING",
"machine": {"class": machine_class_id},
"content": {"initializer": {"specs": [{"context_url": {"url": repo_url}}]}}
}
environment = (await client.environments.create(spec=create_params)).environment
await util.wait_for_environment_running(client, environment.id)
async for line in await util.run_command(client, environment.id, command_to_execute):
print(line)
await client.environments.delete(environment_id=environment.id)
if __name__ == "__main__":
asyncio.run(execute_command_in_environment())
```
This is a simplified example. See the [full examples](https://github.com/gitpod-io/gitpod-sdk-python/tree/main/examples) in the Python SDK repository for production patterns including cleanup handling.
## Examples
| Example | Description | Link |
| ------------------ | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| Run a command | Initialize an environment from a Git repository and run a command | [Python](https://github.com/gitpod-io/gitpod-sdk-python/blob/main/examples/run_command.py) |
| Run a service | Run a long-lived service (database, message queue) in an environment | [Python](https://github.com/gitpod-io/gitpod-sdk-python/blob/main/examples/run_service.py) |
| File system access | Read and write files in an environment programmatically | [Python](https://github.com/gitpod-io/gitpod-sdk-python/blob/main/examples/fs_access.py) |
| SCM authentication | Authenticate with source control providers in an environment | [Python](https://github.com/gitpod-io/gitpod-sdk-python/blob/main/examples/scm_auth.py) |
| Anthropic tool use | Use the Anthropic tool with Model Context Protocol (MCP) | [Python](https://github.com/gitpod-io/gitpod-sdk-python/blob/main/examples/anthropic_tool_use.py) |
| MCP server | MCP server integration | [Go](https://github.com/gitpod-io/gitpod-sdk-go/tree/main/examples/mcp-server) |
# MCP servers
Source: https://ona.com/docs/ona/mcp
Extend Ona Agent with external tools using the Model Context Protocol
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/guide/) extends Ona Agent with external tools like 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). Ona kicks off the OAuth flow so the agent acts with the user'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.
# Announcement banner
Source: https://ona.com/docs/ona/organizations/announcement-banner
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Announcement banners let organization admins communicate important information to all members. Banners appear at the top of the dashboard and persist until disabled.
## Configure the banner
1. Go to **Settings → Organization → Announcements**
2. Enable **Enable announcement banner**
3. Enter your message (up to 1,000 characters)
4. Click **Save**
The banner appears immediately for all organization members.
## Formatting
Banners 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 banner
Toggle off **Enable announcement banner** in the settings. Your message is preserved and can be re-enabled later.
## FAQ
All organization members see the banner when logged in. It appears on every page in the dashboard.
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.
# 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.
# 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. |
## 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.
# 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 Members** 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 and resources. 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 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
# 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)
# 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.
Set a maximum age for new 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 day, 3 days, 1 week, 2 weeks, 1 month, 3 months, 6 months, or no maximum.
Changes apply to new environments only. Existing environments keep their current lifetime.
### 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.
## 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** are not affected. They keep their current lifetime (or have none).
3. When an environment passes its lockdown timestamp, it becomes non-compliant
4. Depending on strict enforcement, restarting is either warned or blocked
The lockdown timestamp is set once at environment creation. Changing the policy duration only affects environments created after the change.
# Environment 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
Select maximum timeout duration: 30 minutes, 1 hour, 3 hours, 8 hours, or No max (includes "Never").
## Effect on users
Users only see timeout options up to the policy maximum. For example, with "3 hours" max, options are: 30 min, 1 hour, 3 hours.
Users can also set an environment's inactivity 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.
* **Ona Agent is running**: The environment is not idle while an Ona AI 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 your configured timeout elapses, the actual auto-stop may occur several minutes later. 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).
# 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). Environment 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 |
| [Environment 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 |
| [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 Ona Agent execution |
| [SCM tools](/docs/ona/organizations/policies/scm-tools) | Control Ona Agent's GitHub/GitLab access |
| [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
# 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)) |
# 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."
# 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.
# 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 |
| **Automations file path** | Path to automation YAML 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 automation 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 automation 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
* **Automation tasks**: Any tasks in your `automations.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/automations-yaml-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
* **Automation 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 automation 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/automations-yaml-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 but may be delayed by up to 15 minutes as they are created in batches.
* **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 load across the system. Your prebuild will start within the scheduled hour, but not necessarily at the exact start of it. Expect up to 15 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 automation 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 automation 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 `automations.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 automations, 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 automations (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 automation services exist for every service required to run any app.
- Ona automation 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 Ona Agent 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/
```
Ona 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.
#### 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.
# 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 and type
* **Action**: Operation performed (e.g., "Environment created")
* **Timestamp**: When
* **Organization**: Which org
## What gets logged
All create, update, and delete operations on:
| Category | Resources |
| -------------- | ---------------------------------------------------------------------------------------------- |
| Infrastructure | Environments, Runners, Projects, Environment Classes |
| Execution | Tasks, Services, Workflows, Agents, and their executions |
| Security | Users, Service Accounts, Tokens, Secrets, SSO Config, Groups, Login/Logout events |
| Organization | [Policies](/docs/ona/organizations/policies/overview), Domain Verification, Custom Domains, Billing |
| Integrations | SCM/LLM Integrations, Prebuilds, Snapshots, Prompts |
**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 0193e2f2-d0b5-7d52-87eb-235deadaf625 PRINCIPAL_RUNNER changed update_time, status, phase, last_running_session 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"
```
**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": "changed status, phase",
"createdAt": "2025-02-21T12:10:05Z"
}
],
"pagination": {
"nextToken": "eyJpZCI6IjAxOTUxZDk0LWQ2YWMtN2VkZi05MDIxLWEwNDRjZmQxOTA4ZiJ9"
}
}
```
## 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 only | 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.
```
Ona uses Anthropic's Claude Opus 4.8, and the use of all-caps *IMPORTANT* and *ALWAYS* is effective to give extra emphasis to rules. See [Teach agents your codebase](/docs/ona/agents-md) for the full guide.
### Tools (Dev Container) and automations
[`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.
[`automations.yaml`](/docs/ona/configuration/tasks-and-services/overview) extends it with tasks and services that automate setup and recurring tasks. Ona Agents can use these automations 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 goal mode is available
* `/fast` toggles Codex fast mode in active Codex conversations when the selected model supports 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 Ona 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.
* **[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).
# 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.
## 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.
## 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 Ona Agent.
Block specific commands from being executed by Ona Agent. 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. User provides input to Ona 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 Ona 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 Ona 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`)
- 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
* 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)
**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 these records in private DNS that is reachable from your users' networks and runner VPCs. Do not publish records that point users to an internal load balancer unless those users resolve DNS and route traffic from connected private networks.
Configure your DNS to point your domain to the load balancer IP address.
1. **Get Load Balancer IP**:
```bash theme={null}
terraform output load_balancer_ip
```
2. **Create DNS Record**:
* In your DNS provider, create an A record:
**Main custom domain record:**
* **Name**: Your custom domain (e.g., `ona.example.com`).
* **Type**: A.
* **Value**: Load Balancer IP address.
**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"
```
> Note: If using an internal load balancer (`load_balancer_type = "internal"`), 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
Destroy any existing runners and create a new one by accessing the management plane from your custom domain. Follow the usual runner creation setup for [AWS](/docs/ona/runners/aws/setup) or for [GCP](/docs/ona/runners/gcp/setup).
**Why this is necessary:** Runners are configured during creation with the management plane URL they should connect to. Existing runners will continue trying to connect via the old domain. Creating a new runner from your custom domain ensures it's configured with the correct endpoint and can properly communicate with the management plane through your infrastructure.
***
## 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. 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)
```
# Veto - Executable Deny List
Source: https://ona.com/docs/ona/organizations/policies/executable-deny-list
Block specific executables from running in organization environments using kernel-level enforcement.
Available on the Enterprise plan. Currently in early access behind a feature flag. [Contact sales](https://ona.com/contact/sales) to learn more.
Prevent specific binaries from executing inside environments. Useful when:
* Blocking known-risky or unauthorized tools (e.g., `npx`) across all environments in your organization
* Enforcing software supply chain policies by preventing dropped binaries from executing
The [OWASP Top 10 for Agentic Applications](https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/) identifies Unexpected Code Execution (ASI05) and Supply Chain Vulnerabilities (ASI04) as top risks for agentic systems. The executable deny list addresses the binary execution aspect of these risks: when an agent, prompt injection, or supply-chain payload attempts to run a known-bad executable, the kernel blocks it regardless of how the execution was triggered.
## How it works
Veto identifies executables by their SHA-256 content hash, not by filename. Enforcement happens entirely in-kernel at the point of execution.
This means:
* **Rename-resistant.** Renaming or copying a blocked binary does not bypass the policy.
* **Symlink-resistant.** Invoking a blocked binary through a chain of symlinks does not bypass the policy.
* **TOCTOU-free.** The hash check and the enforcement decision happen on the same kernel file reference in the same `execve` call.
This is different from the [command deny list](/docs/ona/command-deny-list), which operates at the agent level in userspace and matches commands by pattern. The executable deny list enforces at the kernel level and matches binaries by content.
## Enforcement modes
Each deny list operates in one of two modes:
| Mode | Behavior |
| --------- | --------------------------------------------------- |
| **Block** | Execution is denied (`EPERM`). An event is emitted. |
| **Audit** | Execution is allowed. An event is emitted. |
Use audit mode to understand what *would* be blocked before switching to block mode.
The mode applies to the entire deny list. Per-executable mode selection is not supported in this version.
## Safelist
Ona runtime binaries (supervisor, CLI, SSH) are safelisted by content hash at build time. The safelist always overrides the deny list, so these binaries cannot be blocked.
The safelist is read-only and managed by Ona. It cannot be modified.
Blocking a shell interpreter (e.g., `/bin/bash`) blocks all scripts that use it and can render the environment unusable. Shell safelisting is planned but not yet implemented. Take care when adding interpreters to the deny list.
## Event reporting
Every execution that matches the deny list produces a structured event, regardless of whether the mode is block or audit. Events include:
* SHA-256 digest of the binary
* Kernel-resolved file path
* Enforcement action taken (block or audit)
* Process metadata (PID, command line, parent PID, session ID)
* Timestamp
Events are written to environment logs and reported to the management plane.
## Fail-open behavior
If the kernel cannot compute the content hash for an execution (e.g., due to an internal error), the execution is allowed. The system does not block environments due to its own failures.
## Configuration
1. Go to **Settings → Organization → Policies**
2. Toggle **Enable Executable Deny List**
3. Choose the enforcement mode (**Block** or **Audit**)
4. Enter executable paths, one per line (maximum 50 entries)
5. Click **Save Changes**
Paths should be absolute (e.g., `/usr/bin/wget`). When the policy is applied to an environment, the system resolves each path (following symlinks, translating container paths to host paths) and hashes the binary found there. The system identifies each binary by the SHA-256 hash of its content, not by its path.
## Preview before saving
Test your deny list against a running environment before committing the policy org-wide:
1. Enter executables in the textarea (saving is not required)
2. Click the **Preview in…** dropdown and select a running environment
3. The config is applied immediately to that environment only
4. Open the environment to verify the expected binaries are blocked
5. Modify the list and re-apply as needed. A warning indicator appears when the textarea changes after a preview
Preview applies the deny list to a single environment only. It does not affect the saved organization policy or other environments.
## Effect on environments
* **New environments** receive the deny list on creation
* **Restarted environments** receive the latest deny list on start
* **Already-running environments** are not affected by org policy changes. They keep the deny list they received at start time
# 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.
# 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
Service accounts need Git authentication to clone repositories, commit changes, and create pull requests. Only PAT-based authentication is supported.
### Add Git 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 commits changes, the Git author email is determined by the account that owns the Personal Access Token. 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.
## 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.
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
# automations.yaml schema
Source: https://ona.com/docs/ona/reference/automations-yaml-schema
Field reference for tasks and services in automations.yaml.
Ona loads tasks and services from `.ona/automations.yaml` in your repository root. You can change this location in [Projects](/docs/ona/projects/overview).
```yaml theme={null}
services:
# long-running processes (databases, servers)
tasks:
# one-off actions (build, test, seed)
```
The key (e.g., `database`, `buildAll`) is used to reference the item in dependencies and CLI commands. Keys must match the pattern `^[a-zA-Z0-9_-]{1,128}$` (alphanumeric, underscores, and hyphens, 1-128 characters).
## Service schema
Services are long-running processes that stay active throughout your session.
### Service fields
| Field | Type | Required | Description |
| ------------------ | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | Yes | Display name shown in UI and logs |
| `description` | string | No | Description of what the service does |
| `commands` | object | No | Lifecycle commands (see below) |
| `triggeredBy` | array | No | When to automatically start (see [Triggers](#triggers)) |
| `role` | string | No | Service role: `default`, `editor`, or `ai-agent` |
| `runsOn` | object | No | Execution environment (see [Execution environment](#execution-environment)) |
| `readinessTimeout` | duration | No | Max time to wait for `commands.ready` before startup fails (for example `30m`, `1h`). `0s` disables timeout. Range: `0s-24h` |
### Service commands
The `commands` object controls the service lifecycle:
| Field | Required | Description |
| ------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `start` | Yes (if commands defined) | Command to start and run the service. **Must stay running**: the service is active only while this process is alive. If it exits with code 0, the service transitions to Stopped. Non-zero exit transitions to Failed. |
| `ready` | No | Readiness check command. Runs repeatedly until it exits with code 0. Service stays in Starting phase until ready succeeds. If not set, the service is considered ready as soon as `start` begins running. |
| `stop` | No | Custom stop command. If not set, start receives SIGTERM when stop is requested. If set, stop runs first, then start receives SIGKILL. |
When stopping a service, if the process doesn't exit within 2 minutes, SIGKILL is sent automatically.
### Service example
```yaml theme={null}
services:
database:
name: PostgreSQL
description: The backend database
triggeredBy:
- postEnvironmentStart
commands:
start: docker run --rm --name database postgres:latest
ready: docker exec database pg_isready
stop: docker stop database
backend:
name: Application Backend
description: The application backend
role: default
triggeredBy:
- postEnvironmentStart
commands:
start: cd backend && go run main.go
```
### Service phases
Services transition through these phases during their lifecycle:
| Phase | Description |
| ---------- | -------------------------------------------------------------- |
| `STARTING` | Start command running, readiness check pending (if configured) |
| `RUNNING` | Service is running and ready |
| `STOPPING` | Service is being stopped |
| `STOPPED` | Service stopped normally (exit code 0) |
| `FAILED` | Service failed (non-zero exit code) |
## Task schema
Tasks are one-off actions that run to completion.
### Task fields
| Field | Type | Required | Description |
| ------------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | string | Yes | Display name shown in UI and logs |
| `command` | string | Yes | Shell command to execute |
| `description` | string | No | Description of what the task does |
| `triggeredBy` | array | No | When to automatically run (see [Triggers](#triggers)) |
| `dependsOn` | array | No | Task keys that must complete before this task starts. In a dependency chain, only the final task should have an automatic trigger - dependent tasks are started automatically when needed. |
| `prebuildRequiresSuccess` | boolean | No | When `true` and the task has a `prebuild` or `beforeSnapshot` trigger, a non-successful outcome (failed or stopped) fails the entire prebuild. Defaults to `false` (task failures produce a warning but the prebuild still succeeds). See [Requiring task success in prebuilds](#requiring-task-success-in-prebuilds). |
| `runsOn` | object | No | Execution environment (see [Execution environment](#execution-environment)) |
### Task example
```yaml theme={null}
tasks:
buildAll:
name: Build All
description: Builds all code
command: go build .
runUnitTests:
name: Run unit tests
command: go test -v ./...
dependsOn:
- buildAll
validate:
name: Validate
description: Builds and tests the code
triggeredBy:
- postEnvironmentStart
dependsOn:
- buildAll
- runUnitTests
command: echo "Validation complete"
```
### Task execution phases
Task executions transition through these phases:
| Phase | Description |
| ----------- | ----------------------------------------- |
| `PENDING` | Task waiting to start |
| `RUNNING` | Task is executing |
| `SUCCEEDED` | Task completed successfully (exit code 0) |
| `FAILED` | Task failed (non-zero exit code) |
| `STOPPED` | Task was stopped before completion |
## Triggers
Control when tasks and services run automatically:
| Trigger | Services | Tasks | Description |
| ----------------------- | -------- | ----- | ---------------------------------------------------------------------------------------------------------------------------- |
| `manual` | ✓ | ✓ | Triggered by explicit user action via 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. Does **not** fire when a user environment starts from a prebuild. No user secrets available. |
User secrets are not available during prebuild execution because prebuilds run without user context.
### Additional triggers (API only)
The following triggers can only be set via the [API](/docs/ona/api-reference), not in `automations.yaml`:
| Trigger | Services | Tasks | Description |
| ------------------ | -------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `postMachineStart` | ✓ | ✓ | After the VM starts, before the Dev Container is ready. Requires `runsOn: machine`. Used for machine-level services like security agents. |
| `beforeSnapshot` | ✗ | ✓ | After all prebuild tasks complete, before the snapshot is taken. Used for tasks that must run last during prebuilds, such as IDE warmup. |
### Prebuilds and triggers
During a prebuild, **only** automations (tasks and services) with the `prebuild` trigger run. All other triggers (`postDevcontainerStart`, `postEnvironmentStart`) are skipped. This is intentional: prebuilds run without user context (no user secrets), so running automations during a prebuild is opt-in.
When a user creates an environment from a prebuild, the normal triggers fire: `postDevcontainerStart`, `postEnvironmentStart`, etc. The `prebuild` trigger does **not** fire in user environments.
**Common pattern — tasks**: Use both triggers on the same task when you want it to run during prebuilds *and* when the Dev Container is rebuilt in a user environment:
```yaml theme={null}
tasks:
install-deps:
name: Install dependencies
triggeredBy:
- prebuild
- postDevcontainerStart
command: npm ci
```
In this example, `npm ci` runs during the prebuild (so the snapshot includes `node_modules`) and also runs if a user rebuilds their Dev Container (which creates a fresh container without the snapshot).
**Common pattern — services**: Start a service during prebuilds so that prebuild tasks can depend on it:
```yaml theme={null}
services:
database:
name: Database server
commands:
start: docker run --rm --name database -p 5432:5432 postgres:16
ready: docker exec database pg_isready
triggeredBy:
- prebuild
- postDevcontainerStart
```
The prebuild waits for all services to become ready before snapshotting. Without a `ready` command, the service is considered ready immediately, so the prebuild may snapshot before the service has finished initializing (e.g., before a Docker image is fully pulled). Always define a `ready` command for prebuild services so that setup work is captured in the snapshot. If the service fails, the prebuild still completes.
### Requiring task success in prebuilds
By default, a task that fails during a prebuild produces a warning but the prebuild still succeeds and creates a snapshot. Set `prebuildRequiresSuccess: true` to treat a non-successful outcome (failed or stopped) as a prebuild failure instead — no snapshot is created and the prebuild moves to the **Failed** phase.
This applies only to tasks with a `prebuild` or `beforeSnapshot` trigger. The flag is ignored for other triggers.
```yaml theme={null}
tasks:
build:
name: Build project
triggeredBy:
- prebuild
prebuildRequiresSuccess: true
command: make build
```
If multiple tasks have `prebuildRequiresSuccess: true` and more than one fails, the failure message lists all of them.
## Execution environment
By default, tasks and services run inside the Dev Container. The `runsOn` field lets you change where they execute.
### Run on the host machine
Use `runsOn: machine` to run directly on the VM, outside the Dev Container. This is useful for services that need to start before the Dev Container is ready (e.g., with the `postMachineStart` API trigger) or that need direct access to the host.
```yaml theme={null}
services:
security-agent:
name: Security Agent
commands:
start: /opt/agent/run
runsOn:
machine: {}
```
### Run in a Docker container
Use `runsOn: docker` to run in a separate Docker container with a specific image:
```yaml theme={null}
tasks:
lint:
name: Lint
command: golangci-lint run ./...
runsOn:
docker:
image: golangci/golangci-lint:latest
environment:
- GOLANGCI_LINT_CACHE=/tmp/cache
```
| Field | Type | Required | Description |
| -------------------- | ------ | -------- | -------------------------------------------------- |
| `docker.image` | string | Yes | Docker image to run in |
| `docker.environment` | array | No | Environment variables to set (format: `KEY=VALUE`) |
## Complete example
This example demonstrates all available schema features:
```yaml theme={null}
services:
# Containerized service using docker run
redis:
name: Redis Cache
description: In-memory cache for session data
role: default
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 redis:7-alpine redis-server --appendonly yes
fi
ready: docker exec redis redis-cli ping | grep -q PONG
stop: docker stop redis
# Service running in the Dev Container
backend:
name: API Server
description: Main application backend
triggeredBy:
- postDevcontainerStart
- manual
commands:
start: cd backend && go run main.go
ready: curl -sf http://localhost:8080/health
# AI agent service
code-assistant:
name: Code Assistant
description: AI-powered code analysis
role: ai-agent
triggeredBy:
- manual
commands:
start: ./bin/assistant serve
tasks:
# Task that runs during prebuild (no user secrets available)
install-deps:
name: Install dependencies
description: Install all project dependencies
triggeredBy:
- prebuild
- postDevcontainerStart
command: npm ci && go mod download
# Task with dependencies on other tasks
build:
name: Build project
description: Compile all source code
dependsOn:
- install-deps
command: npm run build && go build ./...
# Lint task
lint:
name: Lint code
description: Run linters
command: golangci-lint run ./...
# Manual task for running tests
test:
name: Run tests
description: Execute the full test suite
triggeredBy:
- manual
dependsOn:
- build
command: npm test && go test -v ./...
```
## Iterating on Tasks and Services
You can iterate on tasks and services using the [CLI](/docs/ona/integrations/cli) which is available by default in every Ona environment. The CLI can
* reload the tasks and services file using:
```bash theme={null}
ona automations update [optional-path-to-automations.yaml]
```
* start a task or service:
```bash theme={null}
ona automations service start ...
ona automations task start ...
```
## Using Tasks and Services outside of an environment
The CLI commands to interact with an environment’s tasks and services are also available outside of an environment. The following snippet brings up an environment, adds a task, runs it, waits for the task to complete and brings the environment back down again:
```bash theme={null}
# ona env create will set the environment context to the newly created env
ona env create https://github.com/some/repo
# add the task to the environment
cat <` | 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 ssh-config` | Configure SSH for direct access |
| `ona environment logs ` | View environment logs |
| `ona environment exec -- ` | [Run a command](/docs/ona/environments/agent-environments#run-commands) inside an environment |
| `ona environment keep-alive` | [Keep environment alive](/docs/ona/organizations/policies/environment-timeout#keep-environment-alive-during-long-running-tasks) while a process runs |
### Partial environment IDs
Instead of typing full UUIDs, 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
# Any substring
ona environment ssh 70a1-beae
```
The CLI resolves the partial ID if it uniquely identifies an environment.
### Environment names
Use `ona environment update` to set or clear a custom name:
```bash theme={null}
ona environment update 019194a6 --name "api-dev"
ona environment update api-dev --name ""
```
Use `--inactivity-timeout` on `create` or `update` to set a custom auto-stop timeout. See [environment timeout](/docs/ona/organizations/policies/environment-timeout) for details.
Most user-facing environment commands accept a full environment ID, unique partial ID, or exact environment name:
```bash theme={null}
ona environment ssh api-dev
ona environment port list api-dev
ona automations task start build --environment-id api-dev
```
Environment name matching is case-insensitive. Environment names are not unique; if a name matches more than one environment, use an environment ID.
Search across environment IDs, names, repository URLs, and branches:
```bash theme={null}
ona environment list --search api-dev
```
Generated SSH aliases and stored CLI contexts remain ID-based. Use `ssh .ona.environment` for direct SSH, or `ona environment ssh ` when you want the CLI to resolve a name.
## Port commands
| Command | Description |
| ---------------------------------------- | ---------------------------------------------------------------- |
| `ona environment port list [id-or-name]` | List open ports |
| `ona environment port open ` | Open a port (supports `--name`, `--protocol`, and `--admission`) |
| `ona environment port close ` | Close a port |
## Dev container commands
| Command | Description |
| ----------------------------------------------------------------------- | ---------------------------------------------------- |
| `ona environment devcontainer rebuild` | Rebuild the dev container |
| `ona environment devcontainer validate .devcontainer/devcontainer.json` | Validate a devcontainer.json file against the schema |
| `ona environment devcontainer logs [id-or-name]` | View dev container build logs (supports `--follow`) |
The environment must be running to rebuild.
## Automation commands
| Command | Description |
| ----------------------------------------- | ----------------------------- |
| `ona automations init` | Initialize automations config |
| `ona automations update automations.yaml` | Update automations from file |
| `ona automations task list` | List tasks |
| `ona automations task start ` | Start a task |
| `ona automations task logs ` | View task logs |
| `ona automations service list` | List services |
| `ona automations service start ` | Start a service |
Use `--environment-id ` to target a specific environment for automation commands.
## Webhook commands
| Command | Description |
| ----------------------------- | -------------------------------------------------------------- |
| `ona webhook create` | Create a webhook (`--name`, `--type`, `--scope`, `--provider`) |
| `ona webhook secret get ` | Get the signing secret for a webhook |
See [Webhooks](/docs/ona/automations/webhooks) for setup and SCM registration.
## Dotfiles commands
| Command | Description |
| ------------------------------------------ | ---------------------------- |
| `ona user dotfiles get` | View current dotfiles config |
| `ona user dotfiles set --repository ` | Set dotfiles repository |
| `ona user dotfiles set` | Clear dotfiles config |
Supports `-o json` and `-o yaml` output. See [dotfiles documentation](/docs/ona/configuration/dotfiles/overview).
## Project and group commands
| Command | Description |
| ---------------------------------- | ---------------- |
| `ona project list` | List projects |
| `ona project create ` | Create a project |
| `ona group list` | List groups |
| `ona group create --name ""` | Create a group |
## Organization security policy commands
| Command | Description |
| ------------------------------------------------------------------- | ---------------------------------------------------- |
| `ona organization security-policy list` | List security policies in the active organization |
| `ona organization security-policy init policy.yaml` | Create and validate a security policy YAML file |
| `ona organization security-policy init policy.yaml --validate-only` | Validate a security policy YAML file |
| `ona organization security-policy create policy.yaml` | Create a security policy from a YAML or JSON file |
| `ona organization security-policy get -o yaml` | Export a security policy |
| `ona organization security-policy update policy.yaml` | Update a security policy from a YAML or JSON file |
| `ona organization security-policy update policy.yaml` | Update a security policy using the ID in the file |
| `ona organization security-policy delete ` | Delete a security policy |
| `ona organization security-policy set-default ` | Use a security policy for newly created environments |
| `ona organization security-policy set-default --clear` | Clear the default security policy |
`create` and `update` accept the YAML emitted by `get -o yaml`, so exported policies can be edited and applied again:
```bash theme={null}
ona organization security-policy get -o yaml > policy.yaml
ona organization security-policy update policy.yaml
```
Pass `--organization-id ` to `list`, `create`, or `set-default` to target an organization other than the active CLI context.
## Identity commands
| Command | Description |
| ----------------------------- | ---------------------------------- |
| `ona whoami` | Show current user and access level |
| `ona login` | Authenticate via browser |
| `ona login --token ""` | Authenticate with PAT |
## Configuration commands
| Command | Description |
| ------------------------------- | ----------------- |
| `ona config context list` | List CLI contexts |
| `ona config context use ` | Switch context |
## Network troubleshooting
Run connectivity checks from your machine against Ona services. Useful for diagnosing DNS, TLS, proxy, or intermittent connection issues.
```bash theme={null}
ona network-troubleshoot
```
The command tests DNS resolution, TCP connections, TLS handshakes, and authenticated API requests. It also checks runner connectivity by discovering runner hosts via the API.
| Flag | Default | Description |
| ---------------- | ------- | ---------------------------------------------------- |
| `--iterations` | `10` | Number of repeated requests |
| `--timeout` | `30s` | Timeout per request |
| `--interval` | `1s` | Interval between requests |
| `--show-headers` | `false` | Show request/response headers and body |
| `--runner-host` | - | Runner hostname(s) to check (bypasses API discovery) |
Use `--runner-host` when the API is unreachable and you need to test runner connectivity directly.
## 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
```
## Version and updates
| Command | Description |
| ----------------------------------- | ----------------------------------------------- |
| `ona version` | Show CLI version |
| `ona version update` | Update to latest version |
| `ona version update --verify-slsa` | Update with SLSA verification |
| `ona config set --verify-slsa=true` | Enable SLSA verification for all future updates |
| `ona config set --autoupdate=true` | Enable automatic updates |
SLSA verification cryptographically proves the CLI binary was built by the official build system. When enabled, every update checks the Sigstore certificate, Rekor transparency log, and provenance metadata. If verification fails, the update aborts.
Configuration is stored at `~/.ona/configuration.yaml`.
## Related
* [CLI installation and setup](/docs/ona/integrations/cli) - install, authenticate, and connect
* [automations.yaml schema](/docs/ona/reference/automations-yaml-schema) - task and service configuration
* [Environment variables](/docs/ona/reference/environment-variables) - variable behavior and availability
# 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)) |
| CloudWatch Logs | Runner task logs |
| Lambda Functions | CloudFormation Custom Resources for network configuration and capacity provider lifecycle (negligible / free tier) |
## 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**.
# 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.0.0/16`, `app.gitpod.io`, and `.amazonaws.com` to NO\_PROXY. See [proxy configuration](/docs/ona/runners/aws/setup#proxy-configuration-optional).
## 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.json`
* `https://app.gitpod.io/releases/ec2/stable/gitpod-ec2-runner-enterprise.json`
* `https://app.gitpod.io/releases/ec2/stable/gitpod-ec2-multi-org-runner.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.0.0/16,app.gitpod.io,.amazonaws.com` |
When configuring a proxy, `No Proxy` must include at minimum: `.internal`, `169.254.0.0/16`, `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
* [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 the support chat (bubble icon in bottom-right). 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).
## 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:**
```bash theme={null}
curl -I -v https://app.gitpod.io
# Windows: curl.exe -I -v -w '\n%{certs}\n' https://app.gitpod.io
```
If issuer shows "Zscaler Inc." instead of "Amazon", SSL inspection is active.
**Fix (recommended):** Add `app.gitpod.io` to SSL inspection bypass list.
**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 blocking IP ranges, OAuth callbacks, or runner-gateway protocols.
**Fix:**
* Whitelist Ona's static IP ranges (see [access requirements](/docs/ona/runners/aws/detailed-access-requirements))
* Ensure WebSocket and gRPC traffic is allowed
* **Workaround:** Use Personal Access Tokens instead of OAuth while configuring
## Configuration checklist
Work with your network team to configure:
**SSL inspection:**
* [ ] Add `app.gitpod.io` to bypass list
* [ ] Verify cert issuer shows "Amazon" not "Zscaler"
**HTTP/2:**
* [ ] Enable HTTP/2 for SSL-inspected traffic in Advanced Settings
**Network:**
* [ ] Whitelist Ona IP ranges
* [ ] Allow WebSocket and gRPC traffic
## Verify configuration
```bash theme={null}
# Check SSL (issuer should be Amazon, not 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
# 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 and warm pools
Dual disk works with [prebuilds](/docs/ona/projects/prebuilds) and [warm pools](/docs/ona/projects/warm-pools).
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.
* 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, 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 Redis credentials 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.
| Variable | Description | Default Value |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `enable_cross_zone_restart` | Creates an earlier data snapshot for stopped dual-disk environments so the runner can recreate the data disk in another zone 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. When provided, the module skips creating that service account and uses the one you supply.
Each pre-created service account must have the correct IAM roles assigned before deployment. See the [IAM configuration guide](https://github.com/gitpod-io/terraform-google-ona-runner/blob/main/docs/iam.md) for the exact roles and permissions required per service account.
```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"
}
```
You can provide a subset. Any service account left empty will be created and managed by the module automatically. The Terraform deployer account will also need fewer IAM permissions when using pre-created service accounts, since it no longer needs `iam.serviceAccounts.create` or `resourcemanager.projects.setIamPolicy` for those accounts.
### 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
* [Google Vertex AI](/docs/ona/agents/llm-providers/google-vertex) - Use Vertex AI as the LLM provider for Ona 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, use the bubble icon located in the bottom right corner of 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, 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_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_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 |
### 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`) per endpoint and model |
| `gitpod_llm_requests_duration_seconds` | Histogram | End-to-end proxy request latency |
| `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_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/overview). 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 [Ona Agent](/docs/ona/agents/overview) 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
* Vertex AI private connectivity
* 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
* [Ona Agent](/docs/ona/agents/overview) for AI-powered 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//.well-known/openid-configuration`.
* Then navigate to *Applications > App clients > Ona* to find the details of the newly created application, and copy the information you'll need in Ona:
* **Client ID**
* **Client secret**
4. Configure OIDC Scopes
The default selection of OIDC scopes in Amazon Cognito doesn't meet the requirements for Ona. Navigate to *App client > Login pages > Edit* and ensure the `Profile` scope is selected.
5. Adjust **Sign-up** settings to your needs
* Disable **Self-registration** if you want to limit access to your application.
* With Sign-up disabled, you may need to manage users under *User management* manually.
6. Continue with the SSO configuration in Ona: [Clicking *Save & Test*](/docs/ona/sso/overview#setting-up-single-sign-on)
# Microsoft Entra ID
Source: https://ona.com/docs/ona/sso/entra
You can set up Single Sign-on (SSO) with Microsoft Entra ID for your team.
This section helps you to create an OIDC application with Microsoft Entra ID. 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 [Microsoft Entra admin center](https://entra.microsoft.com/)
## Create an OIDC application
1. On the [Microsoft Entra admin center](https://entra.microsoft.com/), navigate to *Identity > Applications*.
2. Select **New Registration**.
3. Specify General Settings
* App name, e.g. `Ona`
* Platform: `Web`
* Redirect URI: `https://app.gitpod.io/auth/oidc/callback`
4. Obtain *Client Secret* from the *Certificates & secrets* page
* Once the application is registered, navigate to the subpage *Certificates & secrets* to create and obtain a new client secret.
* Click the **New client secret** button.
* Adjust the expiry of the client secret.
* Then copy the value of the client secret to be pasted in Ona's SSO setup.
5. Configure OIDC Scopes
* The default selection of OIDC scopes in Microsoft Entra ID doesn't meet the requirements for Ona. Navigate to *API permissions > Add a permission* to make the necessary changes.
* Select *Delegated permissions* and *OpenId*, then ensure to enable the following scopes:
* `email`
* `openid`
* `profile`
* Although the `email` claim is part of the standard OIDC specification, depending on the setup, Microsoft Entra ID does not include it by default in ID tokens. Under *Manage*, select *Token configuration* and fix this:
* Click **Add optional claim**.
* Add the `email` scope.
6. Obtain *Issuer URL* from *Endpoints* tab
* Navigate to the *Overview* page and select *Endpoints*.
* Copy the *Authority URL* to be used as *Issuer URL* in Ona's SSO setup.
Validate the **Issuer URL** by checking the [OIDC Discovery](https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols-oidc#find-your-apps-openid-configuration-document-uri) location. In some configurations, the **Issuer URL** needs to be adjusted.
If the *Authority URL* reads like `https://login.microsoftonline.com/{tenant}/v2.0`, the OIDC Discovery location is `https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration`. Open this URL in your browser and check the `issuer` field.
Check the `issuer` field in the OIDC Discovery output and ensure this matches the *Authority URL* (*Issuer URL*). If not, e.g. if it reads like `https://sts.windows.net/{tenant}`, try again with `{authority_url}/v2.0/.well-known/openid-configuration` and use `{authority_url}/v2.0` as *Issuer URL* in Ona's SSO setup.
7. Obtain the *Client ID* from the *Overview* page
* Navigate to the *Overview* page and copy the *Application (client) ID* value to be used as *Client ID* in Ona's SSO setup.
8. Continue with the SSO configuration in Ona: [Clicking *Save & Test*](/docs/ona/sso/overview#setting-up-single-sign-on)
# GitLab SSO
Source: https://ona.com/docs/ona/sso/gitlab
You can set up Single Sign-on (SSO) with GitLab SaaS or a self-hosted GitLab for your team.
This section helps you to create an OIDC application with GitLab. 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:
* If you are setting up SSO with a self-hosted GitLab, make sure you have Admin permissions on that GitLab installation, or work together with the administrator.
* If you are setting up SSO with GitLab SaaS (gitlab.com), it is advised to create the OIDC application in a group, so please make sure you have Group Admin permissions on that group.
## Create an OIDC application
The OIDC application allows you to integrate with Ona.
1. Navigate to *Groups > My Awesome Group > Settings > Applications* (for SaaS) or *Admin Area > Application* (for self-hosted).
2. Click the **Add new application** button.
3. Configure the OIDC application by filling out the form:
* **Name**: `Ona`
* **Redirect URI**: `https://app.gitpod.io/auth/oidc/callback`
* **Confidential**: `Yes`
* **Scopes**:
* `read_user`
* `openid`
* `profile`
* `email`
Then click the **Save Application** button.
4. Obtain the *Client ID* & *Client Secret* from the confirmation screen. This is how to interpret the information:
* **Application ID**: *Client ID*
* **Secret**: *Client Secret*
5. Which *Issuer URL* to use?
* For self-hosted GitLab: `https://your-gitlab-installation.org`
* For GitLab Saas: `https://gitlab.com`
6. Continue with the SSO configuration in Ona: [Clicking *Save & Test*](/docs/ona/sso/overview#setting-up-single-sign-on)
# Google
Source: https://ona.com/docs/ona/sso/google
You can set up Single Sign-on (SSO) with Google for your team.
This page helps you create the Google OAuth/OIDC application Ona needs. You will use the resulting **Client ID**, **Client Secret**, and **Issuer URL** in Ona. For the full organization-side setup, see [Single sign-on (SSO)](/docs/ona/sso/overview).
## Prerequisites
* access to create new [API Credentials](https://console.cloud.google.com/apis/credentials) in your Google Cloud project
* admin access to your Ona organization login settings
## Create an OAuth/OIDC application
The OAuth/OIDC application allows you to integrate with Ona.
1. Navigate to your *Google Cloud Console > API Credentials*.
2. Select **Create Credentials**, and choose **OAuth Client ID**.
3. Configure your *OAuth Client ID* by pasting the **Callback URL** shown in Ona into Google's **Authorized redirect URI** field.
4. Obtain the *Client ID* & *Client Secret* and input these into your Ona Setup page.
5. Use Google's global *Issuer URL*: `https://accounts.google.com`
6. Continue with the SSO configuration in Ona and use **Save & Test** to verify the login flow
## Values to enter in Ona
When you return to Ona, enter:
* **Client ID** from Google
* **Client Secret** from Google
* **Issuer URL**: `https://accounts.google.com`
Then test the configuration before rolling it out to your team.
## Google-specific notes
* Copy the redirect URI from Ona rather than retyping it. This avoids callback mismatches.
* If you use domain-based login in Ona, make sure the relevant email domain is also verified and associated with the Google login provider in Ona.
* If testing fails, the most common cause is an incorrect redirect URI or a mismatch between the Google app and the provider configuration in Ona.
## Next steps
* [Single sign-on (SSO)](/docs/ona/sso/overview)
* [SCIM Provisioning](/docs/ona/scim/overview)
# Okta
Source: https://ona.com/docs/ona/sso/okta
You can set up Single Sign-on (SSO) with Okta for your team.
This section helps you to create an OIDC application with Okta. 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 your Okta instance
* Permission to create an [app integration](https://help.okta.com/oie/en-us/Content/Topics/Apps/apps-overview-get-started.htm)
## Create an OIDC application
1. On the Okta Admin dashboard, navigate to **Applications**.
2. Select **Create App Integration**.
3. Select the following options and click **Next**:
* Sign-in method: `OIDC - Open ID Connect`
* Application type: `Web Application`
4. Specify General Settings
* App integration name, e.g. `Ona`
* Sign-in redirect URIs: `https://app.gitpod.io/auth/oidc/callback`
* Sign-out redirect URIs: `none`
5. Assignments
* Select Okta users or groups which would be allowed to use the integration with Ona.
* Okta lets you [import and synchronize directories](https://help.okta.com/oie/en-us/content/topics/directory/directory-integrations-main.htm?cshid=csh-directory-integrations-main), which then can be assigned to use the integration.
6. Obtain *Client ID* and *Client Secret* from the **General** tab.
7. Obtain *Issuer URL*
* Navigate to *Security > API* in the Okta Admin dashboard.
* Copy the **Issuer URI** of the authorization server you want to use.
8. Continue with the SSO configuration in Ona: [Clicking *Save & Test*](/docs/ona/sso/overview#setting-up-single-sign-on)
# Single sign-on (SSO)
Source: https://ona.com/docs/ona/sso/overview
Overview of SSO options for Ona
Available on the Enterprise plan. [Contact sales](https://ona.com/contact/sales) to learn more.
Single Sign-On (SSO) lets your team log in to Ona using an external Identity Provider (IdP) through OpenID Connect (OIDC). Organization Admins configure login providers, verify email domains, and associate domains with providers.
**Key capabilities:**
* **Multiple email domains per login provider**: Configure several email domains for a single identity provider, for organizations with multiple subsidiaries or acquired companies.
* **Multiple login 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.
## Prerequisites
* **Admin-level access** to your organization settings.
* **Domain/DNS admin privileges** to add a DNS TXT record. Ona uses this record to verify ownership of the domain associated with your organization.
* **An Identity Provider** (e.g., Google, GitLab, Okta, Microsoft Entra ID) that supports OpenID Connect (OIDC). You need to create an OIDC application with your IdP and obtain the **Client ID**, **Client Secret**, and **Issuer URL**.
## Setting up Single Sign-On
Navigate to **Settings > Login & Identity > Login Configuration**. SSO setup involves three components that can be configured in any order:
1. **Login providers** - Configure connections to your Identity Providers
2. **Domains** - Verify ownership of your email domains
3. **Domain associations** - Link verified domains to login providers
### Step 1. Create a login provider
Click **New SSO** to configure how Ona connects with your Identity Provider.
Enter a **display name** for your login provider. This name appears on the login provider card in your settings and on the login selection screen when users sign in.
Provider-specific setup guides:
* [Okta](/docs/ona/sso/okta)
* [Google](/docs/ona/sso/google)
* [GitLab](/docs/ona/sso/gitlab)
* [Entra ID](/docs/ona/sso/entra)
* [Amazon Cognito](/docs/ona/sso/cognito)
* [PingFederate](/docs/ona/sso/pingfederate)
After following the guide for your provider, complete the form with:
* **Client ID**: The identifier for your OIDC application.
* **Client Secret**: Secret key for authenticating with the IdP.
* **Issuer URL**: Endpoint of the OIDC server.
Copy the **Callback URL** from the bottom of this form and paste it into the settings of the OIDC application with the IdP.
#### Testing your configuration
Test the OIDC application by clicking **Test & Continue**. The authentication flow with your Identity Provider opens in a new browser window. Verify the authentication flow works before inviting your team to use SSO login.
### Step 2. Add and verify domains
Domains must be verified before they can be used for SSO login. Verification proves ownership of the email domain.
Click **New Domain** to add a new domain.
#### Verify your domain
Add a **TXT record** to your domain's DNS settings. Copy the name and value for the TXT record from the verification view.
#### Check the status of your domain
After adding the TXT record, click **Verify** to check the status. DNS propagation may take some time.
Once the DNS record has propagated, click **Verify** again to update the status.
Your email domain must be verified before the [Sign in with SSO option](#log-in-with-single-sign-on) appears on the login screen.
### Step 3. Associate domains with login providers
Once you have both a login provider and verified domains, associate the domains with the provider. This tells Ona which identity provider should authenticate users from each email domain.
Click on your login provider and select from the dropdown to add a domain.
A single domain can be associated with multiple login providers within the same organization. This is useful when different teams using the same email domain need to authenticate through different identity providers.
### Multiple domains and providers
You can configure multiple verified domains and multiple login providers to support complex organizational structures.
**Common use cases:**
* **Subsidiaries and acquisitions**: Configure domains for each company (e.g., `acme.com`, `acme.co.uk`, `acquired-company.com`) under a single login provider.
* **Different authentication requirements**: Set up separate providers for employees (Okta) and contractors (Azure AD).
* **Regional teams**: Use different identity providers for teams in different regions.
## Log in with Single Sign-on
### Use your email address
After setting up SSO, log out and return to the login page.
1. Click **Continue with SSO**.
2. Enter your email address and click **Continue**. The domain of your email address **must match** one of the verified domains associated with a login provider.
### Selecting your organization or provider
If your email domain is configured in multiple organizations, or if multiple login providers are associated with the same email domain within your organization, a selection screen appears.
Choose the appropriate option to proceed with authentication through your selected identity provider.
### Use the invite link
1. Go to **Settings > Members > Invite members** and copy the invite link for your domain.
2. When you open the invite link while not logged in, only the active login providers are shown.
## Managing Single Sign-on Access
Only **Organization Admins** can configure, modify, or disable SSO settings.
### Deactivating login providers
A deactivated login provider cannot be used to join your organization. Existing login sessions are not affected.
To deactivate a login provider:
1. Go to **Settings > Login and Security**.
2. Click the toggle switch next to the login provider and confirm the action.
The last remaining login provider cannot be deactivated. This prevents you from losing access to your organization.
## Advanced configuration
### Additional scopes
By default, Ona requests the standard OIDC scopes (`openid`, `email`, `profile`) when authenticating with your Identity Provider. These scopes provide basic user information such as email address, name, and email verification status.
If you need additional claims from your IdP (such as group memberships, roles, or department information), configure **additional scopes** on your login provider. These extra scopes tell the IdP to include the corresponding claims in the ID token returned during sign-in.
To configure additional scopes:
1. Go to **Settings > Login and Security** and click on your login provider.
2. In the **Additional scopes** field, enter a comma-separated list of scopes (e.g., `groups, roles`).
3. Save and test the configuration with **Test & Continue**.
Which scopes are available depends on your Identity Provider. Common examples:
* **Okta**: `groups` includes the user's group memberships.
* **Microsoft Entra ID**: Configure optional claims in your app registration under **Token configuration**.
* **PingFederate**: `groups` or custom scopes defined in your PingFederate configuration.
The IdP decides which claims to include based on the scopes requested and its own configuration. Consult your IdP's documentation for the available scopes and the claims they return.
### Claims expression (CEL)
A **claims expression** is an optional [CEL (Common Expression Language)](https://github.com/google/cel-spec/blob/master/doc/langdef.md) expression evaluated against the OIDC token claims on every login. When configured, the expression must evaluate to `true` for the login to succeed. If it evaluates to `false` or fails, the user is redirected to the login page with an error message.
The expression has access to a `claims` variable containing all claims from the ID token as a map. This includes standard claims (`email`, `email_verified`, `name`, `sub`) and any additional claims made available through [additional scopes](#additional-scopes).
To configure a claims expression:
1. Go to **Settings > Login and Security** and click on your login provider.
2. Enter your expression in the **Claims expression** field.
3. Save and test with **Test & Continue** to verify the expression works as expected.
#### Examples
Require a verified email address:
```cel theme={null}
claims.email_verified == true
```
Restrict login to a specific email domain:
```cel theme={null}
claims.email.endsWith("@example.com")
```
Restrict login to members of a specific group:
```cel theme={null}
"engineering" in claims.groups
```
Combine multiple conditions:
```cel theme={null}
claims.email_verified && "staff" in claims.groups
```
#### Example: restricting login to a specific group
A common use case is limiting access to users who belong to a particular group in your Identity Provider. This requires both additional scopes and a claims expression:
1. **Configure the scope**: Edit your login provider and add `groups` to the **Additional scopes** field. This tells the IdP to include group membership claims in the token.
2. **Set the claims expression**: Enter an expression like `"engineering" in claims.groups` in the **Claims expression** field.
3. **Test the configuration**: Click **Test & Continue**. If your account is a member of the `engineering` group, the test succeeds. Otherwise, you see a denial message.
When a user who is not in the required group attempts to log in, they are redirected to the login page with the message: *"Login denied: your account does not meet the required claims conditions."*
Claims expressions have a maximum length of 4096 characters. The expression must evaluate to a boolean value. Non-boolean results are rejected.
## Problems and solutions
1. Error: *The redirect URI included is not valid.*
Make sure the redirect URI in the OIDC application with your Identity Provider matches the Callback URL shown in Ona, e.g., `https://app.gitpod.io/auth/oidc/callback`.
2. Error: *no such host*
Make sure the **Issuer URL** is correct, e.g., `https://dev-16686455.okta.com`. You can verify the URL by appending `/.well-known/openid-configuration` and opening it in your browser, e.g., `https://dev-16686455.okta.com/.well-known/openid-configuration`.
# PingFederate
Source: https://ona.com/docs/ona/sso/pingfederate
You can set up Single Sign-on (SSO) with PingFederate for your team.
This section helps you to create an OIDC application with PingFederate. 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 your PingFederate instance
* Administrator permissions on PingFederate to create and configure OAuth clients
* Understanding of your organization's authentication flow requirements
## Create an OAuth Client
The OAuth client allows you to integrate with Ona using the OpenID Connect protocol.
Please refer to the [official PingFederate documentation](https://docs.pingidentity.com/pingfederate/12.2/administrators_reference_guide/pf_configuring_oauth_clients.html) for detailed configuration steps.
1. Log in to your PingFederate Administrative Console.
2. Navigate to **Applications → OAuth → Clients**.
3. Click **Add Client** to create a new OAuth client.
4. Configure the OAuth client with the following settings:
* **Client ID**: Generate or specify a unique identifier (you'll need this for Ona)
* **Client Authentication**: Select `Client Secret`
* **Client Secret**: Generate a secure secret (you'll need this for Ona)
* **Allowed Grant Types**: Select `Authorization Code`
* **Redirect URIs**: `https://app.gitpod.io/auth/oidc/callback`
* **Allowed Scopes**: Include at minimum:
* `openid`
* `profile`
* `email`
5. **Configure Token Settings**:
* Set appropriate token lifetimes based on your security policies
* Ensure ID tokens include necessary claims (`sub`, `email`, `name`)
6. **Save the Configuration** and note down:
* **Client ID**: The unique identifier you specified
* **Client Secret**: The generated secret
* **Issuer URL**: Your PingFederate base URL (e.g., `https://your-pingfederate.company.com`)
## Additional Configuration
Depending on your PingFederate setup, you may need to:
* Configure attribute mapping to ensure user information (email, name) is properly passed to Ona
* Set up any required authentication policies or adapters
* Configure session management settings
* Review and adjust any security policies that might affect the integration
## Continue with Ona Configuration
Once you have obtained the *Client ID*, *Client Secret*, and *Issuer URL* from your PingFederate configuration, continue with [Step 1. Create a login provider](/docs/ona/sso/overview#step-1-create-a-login-provider) in Ona.
## Troubleshooting
Ensure the redirect URI in PingFederate exactly matches `https://app.gitpod.io/auth/oidc/callback`.
Verify that your PingFederate configuration includes the required OpenID Connect claims (`sub`, `email`, `profile`).
Check PingFederate logs for detailed error information.
For detailed configuration instructions and troubleshooting, refer to the [PingFederate OAuth Configuration Guide](https://docs.pingidentity.com/pingfederate/12.2/administrators_reference_guide/pf_troubleshooting.html).
# Troubleshooting guide
Source: https://ona.com/docs/ona/troubleshooting
Diagnose issues with environments, runners, and IDEs using support bundles and logs.
Support bundles collect diagnostic data that helps identify and resolve issues. Ona provides support bundles for [environments and conversations](#environment-support-bundles), [runners](#runner-support-bundles), and [automation executions](#automation-execution-support-bundles). For IDE-related issues, see the troubleshooting guide for your [editor or IDE](/docs/ona/editors/overview).
## Environment support bundles
Environment support bundles capture logs, conversation data, and VM diagnostics from a specific environment. The contents vary depending on whether the environment is running or stopped.
### How to download
Download an environment support bundle from any of these locations:
* **Sidebar:** Click the `...` on the environment and select **Download support bundle**.
* **Conversation header:** Click the `...` menu on the conversation and select **Download support bundle**.
* **Chat command:** Type `/support-bundle` in the chat input.
* **Command palette:** Search for **Download support bundle**.
### What's included
**When the environment is running**, the bundle contains:
| Data | Description |
| --------------------------------- | ------------------------------------------------------- |
| Environment logs | Logs from the environment's core services |
| Automation logs | Logs from tasks and services running in the environment |
| VM stats | VM resource usage (CPU, memory) over time |
| Conversation data and diagnostics | Chat history and session context from conversations |
Metrics are only included when the environment is running. If the environment is stopped, the bundle does not contain resource usage data.
When conversations exist, the bundle also includes conversation diagnostics:
| Data | Description |
| --------------------- | ---------------------------------------------------- |
| Conversation history | Full conversation between the user and the agent |
| LLM memory transcript | The agent's internal memory of the session |
| Engine state | Internal state of the agent engine (tokens redacted) |
**When the environment is stopped**, the bundle contains persisted environment logs retrieved from cloud storage. These logs cover the environment's most recent sessions.
## Runner support bundles
Runner support bundles capture logs, metrics, profiling data, and network diagnostics from a self-hosted runner.
Not available for Ona Cloud runners.
### How to download
1. Go to **Settings → Runners**.
2. Locate your runner.
3. Click the `...` menu and select **Download support bundle**.
A download link also appears in the degradation banner when a runner is in a degraded state.
### What's included
| Data | Description |
| ------------------ | ----------------------------------------------------------------------------------- |
| Cloud logs | Runner logs from CloudWatch (AWS) or Cloud Logging (GCP) |
| Local logs | Orchestrator logs, cgroup info, and mount info from the runner host |
| Prometheus metrics | Full metric history in OpenMetrics format (15 min lookback on AWS, 24 hours on GCP) |
| Profiling | pprof profiles: CPU, heap, goroutine, block, mutex, allocs |
| Memory stats | Go runtime and VM memory usage snapshot |
| Build info | Go version, OS, architecture, and build settings |
| Network info | VPC, subnet, and security group configuration (when available) |
## Automation execution support bundles
Support bundles are also available for individual automation execution actions. These combine environment and conversation data with action metadata.
### How to download
Click the `...` menu on an automation execution action and select **Download support bundle**.
## Requesting support
To start a support case, use the Pylon chat widget in the bottom-right corner of the dashboard.
When reporting an issue, attach the relevant support bundles:
* **Environment issues:** Provide both the environment support bundle and the runner support bundle.
* **Runner issues:** The runner support bundle alone is sufficient.
* **IDE issues:** See the troubleshooting section for your [editor or IDE](/docs/ona/editors/overview) for how to export logs.
Review bundle contents before sharing outside your organization.
# Architecture Overview
Source: https://ona.com/docs/ona/understanding/architecture
How the management plane and runners work together to keep your code secure while providing a consistent development experience.
Ona uses a two-plane architecture that separates coordination from execution. This page explains what each plane does, why they're separated, and what data flows between them.
## Two planes
### Management Plane
Hosted by Ona. Handles coordination, identity, and configuration:
* Authentication and identity
* Organization management
* Guardrail enforcement
* Runner coordination
* Dashboard and API
### Runners
Run on [Ona Cloud](/docs/ona/runners/ona-cloud) or in your own infrastructure ([AWS](/docs/ona/runners/aws/overview), [GCP](/docs/ona/runners/gcp/overview)). Handle everything that touches your code:
* Environment provisioning
* Source code access
* Secret injection
* Agent execution
* Build and test execution
## Why the split
The separation exists for three reasons:
**Data sovereignty.** Your source code and SCM credentials are handled by runners, not the management plane. With a runner in your VPC, all sensitive assets stay in your infrastructure. With [Ona Cloud](/docs/ona/runners/ona-cloud), code runs on Ona-managed infrastructure separate from the management plane. You choose the trade-off between convenience and control.
**Compliance.** Audit logs track every action. Guardrails are defined centrally and enforced at the runner level. The management plane sets the rules; runners enforce them during execution.
**Flexibility.** You can deploy runners in different regions and cloud providers. Each runner can have different environment classes with different compute specs. The management plane coordinates across all of them.
## Data flow
The diagram below shows what stays in each plane:
## Next steps
* [Core components](/docs/ona/understanding/core-components): what each part of Ona does
* [Runners overview](/docs/ona/runners/overview): where your environments and agents execute
* [Guardrails](/docs/ona/guardrails/overview): configure guardrails and compliance controls
# Core Components
Source: https://ona.com/docs/ona/understanding/core-components
The five building blocks of Ona and how they work together.
Ona is built from five core components. Each serves a distinct role, and together they form the complete platform.
## Environments
Secure, ephemeral VMs provisioned from a [Dev Container](/docs/ona/configuration/devcontainer/overview) configuration. Each environment has its own compute, storage, and networking, pre-loaded with your project's tools and dependencies.
Environments are disposable: create one from a branch, do your work, and discard it. Storage persists across stop/start cycles but not across rebuilds, so the Dev Container configuration is the source of truth for what's installed.
* [Environments](/docs/ona/environments/overview): configure, launch, and manage development environments
## Agents
AI software engineers that execute tasks inside environments: writing code, running tests, and opening pull requests. Agents operate under the same guardrails as human developers, using the same tools and dependencies defined in the environment.
When you assign a task, the agent provisions a fresh environment, reads your project's configuration and [skills](/docs/ona/agents/skills), and works autonomously (writing code, running tests, iterating on failures). It can open a pull request for your review. The workflow runs inside the same isolated environment a human developer would use. No special permissions or separate toolchains.
* [Agents](/docs/ona/agents/overview): learn what Ona Agent can do and how to configure it
## Runners
Infrastructure that provisions and manages environments. Runners can be deployed in your cloud account ([AWS](/docs/ona/runners/aws/overview), [GCP](/docs/ona/runners/gcp/overview)) for full control over security and data residency, or you can use [Ona Cloud](/docs/ona/runners/ona-cloud) for zero-setup managed infrastructure.
* [Runners](/docs/ona/runners/overview): deployment options and shared capabilities
## Guardrails
Identity controls, audit capabilities, and enforcement rules that govern how environments and agents operate. Guardrails include [organization policies](/docs/ona/organizations/policies/overview), [SSO](/docs/ona/sso/overview), [OIDC](/docs/ona/configuration/oidc), [audit logs](/docs/ona/audit-logs/overview), and [command deny lists](/docs/ona/command-deny-list).
* [Guardrails](/docs/ona/guardrails/overview): set up guardrails, compliance, and governance controls
## Automations
Workflows that run on demand, on a schedule, or in response to events like pull requests. Automations combine agent prompts, commands, and integrations to execute changes across your codebase at scale.
Automations support three trigger types: **manual** (on-demand via the dashboard or API), **pull request** (fired on PR events like open or update), and **scheduled** (cron-based recurring runs). Unlike [tasks and services](/docs/ona/configuration/tasks-and-services/overview) which run inside a single environment, automations operate at the organization level and can span multiple repositories.
* [Automations](/docs/ona/automations/overview): create and manage automations
For a deeper look at how these components interact, see the [Architecture overview](/docs/ona/understanding/architecture).
# How Ona Works
Source: https://ona.com/docs/ona/understanding/how-ona-works
Understand how Ona combines environments, agents, and runners to deliver a complete development platform.
Ona is the platform for running background agents at scale. It provides secure, isolated environments pre-configured with your code, tools, and dependencies, the same environments human developers use. Ona runs background agents that write code, fix bugs, run tests, and open pull requests autonomously, triggered by schedules, issues, errors, or messages from your team.
## Your code stays in your infrastructure
Ona has a two-plane architecture:
* **Management plane** (hosted by Ona): authentication, organization settings, guardrails, and coordination. This is the dashboard, CLI, and API.
* **Runners** (your cloud or Ona Cloud): provision environments, access source code, inject secrets, and execute agents.
The split is a security boundary. Source code, credentials, and build artifacts are handled by runners. They never reach the management plane. With a [runner in your VPC](/docs/ona/runners/overview), everything stays in your network. With [Ona Cloud](/docs/ona/runners/ona-cloud), Ona manages the runner infrastructure for you.
For the full data flow, see the [architecture overview](/docs/ona/understanding/architecture).
## Environments
Every task gets its own environment: an isolated VM with dedicated compute, storage, and networking, provisioned from a [Dev Container](/docs/ona/configuration/devcontainer/overview) configuration. Dependencies install, services start, and the workspace is ready. With [prebuilds](/docs/ona/projects/prebuilds), this takes seconds.
Environments are ephemeral. Create one from a branch, do the work, discard it. One environment per task means no file conflicts and straightforward rollback.
## Agents
[Ona Agent](/docs/ona/agents/overview) runs inside environments with the same tools a human developer uses. Give it a task (a bug to fix, a feature to build, a test to write) and it works autonomously: reading code, making changes, running tests, iterating on failures, and opening a pull request.
Agents are guided by [AGENTS.md](/docs/ona/agents-md) (your codebase conventions) and [skills](/docs/ona/skills) (reusable prompts your team encodes). Multiple agents run in parallel across different environments and projects.
## Automations
[Automations](/docs/ona/automations/configure-automations) turn agents into background workers. Trigger them from Linear issues, Sentry errors, webhooks, or cron schedules. Each automation runs in its own environment with full access to your codebase and integrations.
Examples: pick up the top Linear ticket every morning and open a draft PR. Triage new Sentry errors automatically. Scan for CVEs and submit dependency updates. See [templates](https://ona.com/templates) for ready-made workflows.
## Guardrails
Agents operate under the same [guardrails](/docs/ona/guardrails/overview) as human developers. Organization admins control what agents can and cannot do:
* **[Command deny list](/docs/ona/command-deny-list)**: block risky commands across the organization
* **[Veto](/docs/ona/guardrails/veto)**: kernel-level enforcement that blocks unauthorized executables, below the agent's reach
* **[Audit logs](/docs/ona/audit-logs/overview)**: track every action for compliance and incident response
* **[SSO](/docs/ona/sso/overview) and [OIDC](/docs/ona/configuration/oidc)**: identity integration and short-lived cloud credentials
## Next steps
* [Quickstart](/docs/ona/quickstart): get your first environment running in 5 minutes
* [Best practices](/docs/ona/best-practices): prompting, planning, and workflows that work
* [Core components](/docs/ona/understanding/core-components): what each part of Ona does
* [Architecture overview](/docs/ona/understanding/architecture): how the management plane and runners interact in detail
# Workflows
Source: https://ona.com/docs/ona/workflows
End-to-end recipes for common tasks with Ona Agent.
Ona works best when you treat it like a teammate with explicit context and a clear definition of "done." This page gives end-to-end recipes for common tasks.
If you are new to Ona, read [Best practices](/docs/ona/best-practices) first, then come back here for concrete recipes.
## How to read these recipes
Each recipe includes:
* **When to use it**: what task this solves.
* **Steps**: with example prompts.
* **Context notes**: what Ona sees automatically vs what you should provide.
* **Verification**: how to check the output.
***
## Explore a codebase
Use this when you are onboarding, inheriting a service, or trying to understand a request flow.
**Steps:**
1. Open a new environment for the repository.
2. Prompt Ona with the area you want to understand:
```
Explain how the authentication flow works in this codebase.
Include:
- A summary of each module's responsibilities
- What data is validated and where
- One or two gotchas to watch for when changing this
```
3. Follow up with specific questions:
```
Summarize the request flow as a numbered list of steps. List the files involved.
```
**Context notes:**
* Ona reads your AGENTS.md and codebase automatically.
* For large monorepos, point Ona at the relevant directory: "Focus on the `backend/auth/` directory."
**Verification:**
* Ask Ona to produce a checklist or diagram you can validate against the code.
***
## Fix a bug
Use this when you have a failing behavior you can reproduce.
**Steps:**
1. Give Ona a reproduction recipe and the files you suspect:
```
Bug: Clicking "Save" on the settings screen shows "Saved" but doesn't persist.
Repro:
1. Start the app: npm run dev
2. Go to /settings
3. Toggle "Enable alerts"
4. Click Save
5. Refresh: the toggle resets
Constraints:
- Do not change the API shape.
- Keep the fix minimal and add a regression test.
Start by reproducing the bug, then propose a patch and run checks.
```
**Context notes:**
* You provide: repro steps and constraints. These matter more than a high-level description.
* Ona provides: command output, discovered call sites, and any stack traces it triggers.
**Verification:**
* Ask Ona to re-run the repro steps after the fix:
```
After the fix, run lint + the smallest relevant test suite. Report the commands and results.
```
***
## Write tests
Use this when you want to add test coverage for existing code.
**Steps:**
1. Point Ona at the function or module:
```
Add a test for the invert_list function in src/transform.ts.
Cover the happy path plus edge cases.
Follow conventions used in other tests in this directory.
```
**Context notes:**
* Ona reads existing test files to match conventions (test framework, assertion style, file naming).
* For table-driven tests, mention the pattern: "Use the same table-driven pattern as the other tests in this package."
**Verification:**
* Ask Ona to run the tests and report results:
```
Run the test suite for this package and report pass/fail.
```
***
## Prototype from a screenshot
Use this when you have a design mock or UI reference and want a working prototype.
**Steps:**
1. [Attach the image](/docs/ona/agents/image-attachments) by dropping it into the prompt box or pasting from clipboard.
2. Provide constraints and structure:
```
Create a new dashboard page based on this image.
Constraints:
- Use React, Vite, and Tailwind. Write in TypeScript.
- Match spacing, typography, and layout as closely as possible.
Deliverables:
- A new route/page that renders the UI
- Any small components needed
- Instructions to run it locally
```
**Context notes:**
* The image provides visual requirements, but you still need to specify implementation constraints (framework, routing, component style).
* For non-obvious behavior, describe it in text: hover states, validation rules, keyboard interactions.
**Verification:**
* Ask Ona to start a preview server:
```
Start a preview server and give me the URL to view the prototype.
```
***
## Raise a pull request
Use this when you are done with changes and want to open a PR following your team's conventions.
**Steps:**
1. Encode your PR process in a `/create-pr` skill (see [Skills](/docs/ona/skills)). Or use a prompt directly:
```
Raise a draft PR for a branch starting with my initials.
Get my initials from the configured git username.
Check for manual file changes before creating the PR description.
Make sure you capture all changes in this environment.
Follow this template:
## Description
## Related Issue(s)
Fixes
## How to test
```
**Context notes:**
* Ona reads your git config for username and branch naming.
* If your SCM is connected under **Organization Settings > Integrations**, Ona can open the PR directly.
**Verification:**
* Check the PR on GitHub/GitLab. Verify the description, linked issues, and branch name match your conventions.
***
## Review code
Use this when you want a second set of eyes before committing or creating a PR.
**Steps:**
1. Ask Ona to review your changes:
```
Review the changes in this environment. Focus on edge cases and security issues.
```
2. For PR reviews, point Ona at the PR:
```
Review PR #123. Focus on architectural decisions and test coverage.
```
**Context notes:**
* Ona reads the diff, existing tests, and AGENTS.md for project conventions.
* For focused reviews, specify the area: "Focus on the database migration changes."
**Verification:**
* Apply fixes based on review feedback, then ask for a follow-up review to confirm issues are resolved.
***
## Encode a reviewer's style
Use this when you want to capture a specific engineer's review approach and make it available to the team.
**Steps:**
1. Make sure your SCM is connected under **Organization Settings > Integrations**.
2. Run this meta-prompt, replacing `[REVIEWER_NAME]` with the person's name:
```
Analyze the pull request reviews from [REVIEWER_NAME] over the past 30 days. Focus on:
1. Review patterns and style:
- What aspects of code does [REVIEWER_NAME] consistently examine?
- What's their commenting style (direct, questioning, suggestive)?
- How do they balance criticism with encouragement?
2. Technical focus areas:
- Which code patterns do they frequently flag?
- What performance or security concerns do they raise?
- Which best practices do they enforce?
3. Common corrections and suggestions:
- What mistakes does [REVIEWER_NAME] repeatedly catch?
- What refactoring patterns do they suggest?
- Which architectural principles do they advocate?
4. Values and priorities:
- What non-functional requirements matter to them (readability, maintainability, performance)?
- How do they weigh tradeoffs?
- What makes them approve enthusiastically vs. reluctantly?
Transform these observations into a structured review prompt that captures [REVIEWER_NAME]'s review methodology. The prompt should guide an AI to review code with the same attention to detail, technical standards, and communication style.
Format the output as a prompt that begins with: "Review this code as [REVIEWER_NAME] would, focusing on..."
```
3. Save the generated prompt as a `/review-like-[name]` skill under [Settings > Agents > Skills](https://app.ona.com/settings/agent-skills).
**Context notes:**
* This requires SCM integration so Ona can read the reviewer's past PR comments.
* The generated prompt works best when the reviewer has at least 10-15 reviews in the last 30 days.
**Verification:**
* Run the new skill on a recent PR and compare its feedback to what the reviewer would actually say.
***
## Generate a weekly digest
Use this when you want a summary of your team's engineering activity.
**Steps:**
1. Run this prompt at the end of each week (or set it up as an [automation](/docs/ona/automations/configure-automations)):
```
Generate a focused weekly digest that gives the team actionable insight
into our software engineering activity.
Structure the digest as follows:
- Team Output and Productivity: Summarize total commits, merged pull
requests, and notable achievements. Highlight metrics that reflect
productivity, such as lead time for changes and the number of
reviewed issues.
- Code Churn Focus: Identify the three files with the highest code
churn this week (those with the largest combined lines added and
removed). For each file, list:
- The complete file path
- Total lines changed (added plus removed)
- A concise summary of the nature of the changes, inferred from
commit messages
- Inconsistencies and new patterns: Find code patterns, library use
and API definitions that are inconsistent with previous code.
- Shareable Output: Format the digest so it can be posted or forwarded.
Use clear section headers and bullet points.
Also, give me a histogram of commits by author.
Note: we squash PRs when they land on main.
```
**Context notes:**
* Ona reads git history and PR metadata from your connected SCM.
* For monorepos, scope the digest: "Focus on the `backend/` directory."
**Verification:**
* Spot-check a few entries against the actual PRs merged that week.
***
## Measure agent adoption
Use this when you want to track how much of your codebase is being written with agent assistance.
**Steps:**
1. Run this prompt:
```
What's the percentage of commits with Ona contributions merged to main
in the last four weeks?
Give me a daily histogram and weekly average.
Beware that we squash commits when we merge to main.
```
**Context notes:**
* Ona marks itself as a co-author on commits it contributes to. This prompt counts those co-authored commits.
**Verification:**
* Cross-check a few commits manually with `git log --format="%H %s" --grep="Co-authored-by: Ona"`.
***
## Compare before vs after
Use this for design work and fine adjustments where you want a visual comparison of your changes.
**Steps:**
1. Make your changes first, then ask Ona to generate a comparison page:
```
Generate a standalone demo page that visually compares the Before vs
After state of my changes.
Requirements:
- Two side-by-side panels: Before and After
- Exact measurements labeled (e.g., old-value vs new-value)
- Visual rulers showing width/height differences where applicable
- Code snippets comparing old vs new implementation
- Technical Details section with Problem, Solution, and Benefits
- Responsive design for mobile viewing
Process:
1. Create the demo HTML page
2. Start a preview server for the demo HTML page
3. Report the URL of the preview server
```
**Context notes:**
* Ona needs access to both the old and new state. If you haven't committed the old state, Ona can use git diff to reconstruct it.
**Verification:**
* Open the preview URL on both desktop and mobile to verify the comparison renders correctly.
# AWS Runner Releases
Source: https://ona.com/docs/release-notes/aws-runner
Version releases and infrastructure updates for the AWS EC2 runner
## Security and reliability updates
This release updates security-sensitive runner, proxy, and VM image components and fixes several environment startup and agent reliability issues. No infrastructure upgrade is required.
* VM image components were rebuilt with patched Go toolchains, including updates for Go-built binaries and Docker BuildKit.
* Docker, containerd, Docker Compose, and Docker Engine were updated to address critical vulnerabilities in the environment image.
* Runner Go dependencies were updated for security fixes across networking, cryptography, tracing, storage, and SSH-related packages.
* The runner proxy no longer includes the unused Nebula gateway mode, removing a vulnerable dependency from the proxy binary.
* Agent requests reconnect faster after transient runner connection issues.
* Agent conversation archives converge more reliably after interruptions.
* Automation task failures now propagate the failing step exit code instead of marking the step as done.
* Automation services reconcile faster after service status changes and systemd job completion.
* Environment startup is more reliable when SSH proxy port binding, devcontainer defaults, or workspace folder status reporting are involved.
## Patch release
This is a patch release with tagging improvements and reliability fixes. No infrastructure upgrade is required.
* AWS Marketplace revenue attribution tags now propagate to environment VMs, instead of only CloudFormation-managed resources.
* File content reads (regular reads, read-only mmap, mprotect) can now be audited or blocked through veto-file security policies.
* Library lookup caching in the security agent is shared across processes with the same root identity, reducing startup overhead.
* Agent conversation history loads more reliably with a longer initial timeout and smaller page sizes.
* MCP configuration is retried during agent startup, preventing sessions from launching without tool integrations when setup is briefly delayed.
## Horizontal scaling for AWS runners
AWS runners now scale better with load. Starting with this release, runner and proxy horizontal scaling are generally available for AWS runners.
Small runners start with one runner replica and can scale up to 8 replicas. Large runners start with two runner replicas and can scale up to 16 replicas. The proxy also scales horizontally, up to 8 replicas on small runners and 16 replicas on large runners. This adds capacity for busy runners without changing environment VM sizing.
## Infrastructure upgrade required
This upgrade does not cause downtime. The CloudFormation stack update enables runner and proxy scaling and hardens metrics sidecar task definitions. Running environments are not affected.
The upgrade updates the Fargate service scaling configuration, adds required Application Auto Scaling permissions, and sets the ADOT metrics sidecar containers to use read-only root filesystems.
To upgrade, go to **Settings > Runners**, select your runner, open the three-dot menu, and click **Upgrade runner**. See the [upgrade documentation](/docs/ona/runners/aws/update-runner#upgrade-runner-infrastructure) for step-by-step instructions.
## What else is in this release
* VM setup downloads now retry transient network failures and log better diagnostics when a component download fails.
* Ona agent sessions now wait for devcontainer rebuilds and restarts before reconnecting, preventing avoidable connection failures.
* Live agent streams now include request-level logs for connections, state events, and disconnects, making stuck streams easier to diagnose.
* Container service status is updated when the devcontainer stops, preventing stale `RUNNING` states.
* Runner sync and event handling use larger batches and buffers, reducing backend load at high environment counts.
* Deleted runner cleanup now covers orphaned EBS volumes and snapshots, and reverts boosted EBS IOPS and throughput before cleanup.
* Security updates refresh the EC2 orchestrator base image and containerd dependencies.
## Increased runner capacity for large deployments
Large runners now use 16 vCPU and 32 GB of memory, up from 8 vCPU and 16 GB. This fixes CPU saturation observed on busy runners handling hundreds of concurrent environments. No configuration changes are needed. The new sizing takes effect after the infrastructure upgrade.
## Infrastructure upgrade required
This upgrade does not cause downtime. The CloudFormation stack update adds new scaling policies and adjusts task sizing. Running environments are not affected.
The upgrade updates the Fargate task definition and adds a memory-based scaling policy for the proxy service.
To upgrade, go to **Settings > Runners**, select your runner, open the three-dot menu, and click **Upgrade runner**. See the [upgrade documentation](/docs/ona/runners/aws/update-runner#upgrade-runner-infrastructure) for step-by-step instructions.
## What else is in this release
* Proxy service now scales on memory utilization in addition to CPU, preventing exhaustion from long-lived connections.
* Shell history is now shared across terminal tabs within the same environment for bash and zsh.
* Ona agent sessions resume immediately when a devcontainer rebuild finishes.
## Availability Zone capacity fallback
Environment launches now automatically retry in a different Availability Zone when one runs out of EC2 capacity, instead of failing immediately. Fallback subnets are tried in random order to distribute load evenly. This eliminates a class of launch failures observed during high-concurrency workloads where a single AZ exhausts its instance capacity while others remain available.
## What else is in this release
* Environments are no longer incorrectly reported as stopped during shard handoff on multi-replica runners, preventing orphaned VMs.
* Agent executions are no longer orphaned or duplicated after shard handoff. Reconcilers are drained on lost shards and pending work is re-discovered on the new owner.
* Environments stopped by the disconnected timeout now restart correctly when a user sends a new message to an agent, instead of hanging indefinitely.
* Supervisor restart no longer fails when orphaned child processes hold the SSH proxy port. All processes in the supervisor cgroup are now terminated on stop.
* Load balancer health checks verify the proxy is serving HTTP responses instead of only checking TCP connectivity.
* Security dependency upgrades address critical and high-severity CVEs in pgx, go-jose, jsonparser, and OpenTelemetry exporters.
## Security: Ubuntu 26.04 and CVE reduction
Environment VMs now run Ubuntu 26.04 with kernel 7.0, reducing total CVEs from 6,731 to 275 (96% reduction). The Docker stack is bumped to 29.4.3, BuildKit to v0.29.0, and all rootfs binaries are compiled with Go 1.25.10, fixing 12 additional Go stdlib CVEs.
## What else is in this release
* Environments no longer get stuck in STOPPING state. Snapshot preparation gives up after 10 minutes on transport errors instead of retrying indefinitely, and batch stop failures fall back to stopping instances individually.
* Environments stopped by the disconnected timeout are no longer restarted by the agent reconciler, fixing a \~36-minute bounce loop.
* On dual-disk runners, the data disk resize now completes before content initialization starts, fixing `ENOSPC` errors with large container images.
* Warm pool claims work correctly across workers on multi-replica runners, preventing unnecessary cold launches.
* Prebuild environments start with a clean data disk instead of inheriting stale base snapshots.
* Bitbucket repository search and organization listing work again after Bitbucket deprecated cross-workspace APIs.
* Agent goal status now reaches the dashboard correctly.
* Inline image data in agent conversations is offloaded to blob storage before entering live streams and history, reducing bandwidth.
* Runner updates apply with zero downtime. New Fargate tasks are healthy before old ones drain.
* Agent executions are picked up immediately after shard handoff on multi-replica runners, instead of waiting up to 1 hour.
* Agent conversation streams are protected against corruption during shard handoffs on multi-replica runners.
* Agent conversation history loads up to 10x faster for long conversations.
## Faster startup and credential redaction
Environment startup is faster. Disk warming for startup-critical paths now runs in parallel, host binaries (`docker`, `containerd`, `runc`, `node`, `buildkitd`) are pre-warmed alongside data disk paths, and warm pool scaling targets adapt dynamically to EBS snapshot size so large prebuilds are fully hydrated before instances are claimed.
Credentials printed to process output (AWS keys, GitHub tokens, bearer tokens, basic-auth URLs) are now redacted before they reach environment status messages, on-disk state, logs, and tracing spans.
This release also patches CVE-2026-5450 (Critical, glibc) along with four High-severity CVEs in glibc and OpenSSL via a base image digest bump.
## What else is in this release
* Automation services support a configurable readiness timeout. Environments where the supervisor fails to start are now stopped instead of hanging indefinitely.
* The SCM organization list in the project creation flow supports pagination and search for GitLab.
* Prebuild snapshots correctly take precedence over base snapshots on dual-disk environments, fixing cases where prebuild data was discarded.
* The prebuild executor's git identity is cleared from the data disk before snapshot, preventing identity leakage to environments started from that prebuild.
* Binary downloads use atomic writes to prevent truncated files. SHA-256 mismatches are retried automatically.
* The supervisor recovers from stale git config lock files left after an unclean shutdown, instead of entering a panic loop.
* File watch self-healing for the security agent works correctly in Docker-in-Docker environments, including after devcontainer rebuilds.
* AWS `DescribeImages` API calls are scoped to owned AMIs, reducing hundreds of paginated API calls per sync cycle to a handful.
* The runner proxy auto-scales (2-5 replicas) and uses larger task sizes for large runners.
* Environment logs remain accessible after instance termination.
* Updated VM images for AWS runners.
* CloudFormation descriptions updated to use Ona branding.
## Performance and operational improvements
This release improves startup performance, reliability, and operational visibility for EC2 runners. To that end, this release introduces a managed metrics pipeline that lets you export runner metrics for monitoring runner health, environment lifecycle, and resource utilization. Every payload is written to S3 for auditing. Contact your account team to enable it.
* Terminals are now killed when the dev container is rebuilt, preventing unresponsive sessions after a rebuild.
* When multiple MCP servers expose tools with the same name, tool names are automatically prefixed with the server name to prevent silent overwrites.
* Environment startup is faster. Independent supervisor initialization steps now run concurrently, and disk pre-warming runs for all instances with startup-critical paths prioritized.
* SCM context parsing uses ETag-based caching, reducing latency for repeated operations.
* Environments with a configured idle timeout now auto-stop correctly when all SSH connections close.
* OAuth token refresh is more resilient. The token cache is invalidated on permanent errors, and retries use exponential backoff.
* The "All Changes" diff view no longer shows stale or empty results when starting environments from pull requests.
* Git status parsing correctly handles renamed files, fixing broken tree rendering and diff fetching.
* Devcontainer features referenced by local path no longer break the cache key computation.
* Instances under memory pressure now receive stop commands promptly.
* The `ReadFile` API no longer returns stale content due to cache collisions.
* CORS headers are now set on the in-environment browser proxy, fixing silent failures for cross-origin requests.
* Agent SCM tool registration errors are no longer fatal, preventing empty system prompts when tool setup fails.
* The runner-side agent now shows the "MCP servers taking longer than expected" warning.
* GitHub PR agent reactions fire reliably when mentioning the agent.
* Core dumps are disabled at supervisor startup, preventing potential secret leakage.
* Updated Node.js to v24.14.1 (security) and BuildKit to v0.28.1.
## Faster startup and reliability improvements
Environment startup is 1-2 seconds faster. Automation trigger API calls now run in parallel instead of sequentially, and the devcontainer reconciler caches configuration reads in steady state, saving an additional \~130ms per cycle.
## What else is in this release
* Automation-triggered agent executions no longer get stuck in a waiting state when the agent attempts to ask for user input. The request is rejected immediately so the agent can proceed autonomously.
* File watch self-healing now works correctly in all configurations. The discovery agent starts when watch mode is enabled, and the path denylist updates after a denylisted file is unlinked and recreated.
* BPF watch-only mode emits `WATCH_WRITE` and `WATCH_MMAP` events correctly when untouchable mode is off.
* Fixed a runner manager startup panic when multiple managed runners run in the same process.
* Updated VM images for AWS runners.
* Security dependency update: `go-jose/v4` bumped to v4.1.4 (fixes GHSA-78h2-9frx-2jm8).
## Warm pools now GA
[Warm pools](/docs/ona/projects/warm-pools) keep pre-initialized EC2 instances running from the latest prebuild snapshot. When you create an environment, Ona claims an instance that is already running with the snapshot loaded instead of launching a new one. Startup drops from minutes to around 10 seconds.
Enable warm pools per environment class in your project's prebuild settings. The runner dynamically scales the pool between 0 and your configured maximum (up to 10 in the dashboard, up to 20 via the CLI) based on demand. It also handles replenishment and automatic snapshot rotation when new prebuilds complete.
Requires an [Enterprise plan](https://ona.com/pricing). Currently available on EC2 runners only. See the [warm pools documentation](/docs/ona/projects/warm-pools) for prerequisites and setup instructions.
## Infrastructure upgrade required
This release requires a CloudFormation stack update.
This upgrade causes approximately 10-15 minutes of downtime where environments are unreachable. Schedule it during a low-usage period.
The full update takes \~30 minutes. **Your data and environments are preserved.** Running environments reconnect automatically after the update completes.
#### Before you upgrade
1. **Note your Prometheus metrics settings.** The upgrade resets them. You will re-enter them afterward.
See [Custom metrics pipeline](/docs/ona/runners/monitoring-and-metrics).
2. **Internet Gateway users (no NAT gateway):** You **must** set **Assign Public IP** to `true` in the Network Configuration section during the CloudFormation parameter review step.
3. **Templates from January 2025 or earlier:** Either stop and discard existing environments before upgrading, or add port 22 to your security group first.
#### Upgrade steps
1. Go to **Settings > Runners** and select your runner
2. Open the three-dot menu and click **Upgrade runner**
3. Follow the dialog to update your CloudFormation stack
4. Re-enter your Prometheus metrics settings after the update completes
Full walkthrough: [Upgrade runner infrastructure](/docs/ona/runners/aws/update-runner#upgrade-runner-infrastructure)
## What else is in this release
* **Fargate** replaces EC2 instances for the runner service. No more AMI allowlisting or update bottlenecks.
* **MemoryDB** persists Ona agent conversations in real time, with S3 as a durable backup. This is a new billable AWS resource in your account.
* **Runner sizing** lets you choose between `small` and `large` infrastructure via a CloudFormation parameter. Select `large` if your organization runs many concurrent agent sessions.
* **Runner update windows** let you control when your runner applies updates. Set a maintenance window to avoid disruptions during peak hours.
* Environment startup is faster thanks to earlier Docker socket activation and optimized content initialization.
* Runner updates no longer cause brief user disconnects. The proxy now runs as a separate service.
# GCP Runner Releases
Source: https://ona.com/docs/release-notes/gcp-runner
Version releases and infrastructure updates for the GCP runner
## Dual-disk recovery and capacity fallback
GCP runners can recover dual-disk environments more reliably after the original VM is gone. Environments with preserved data disks or completed data snapshots can be listed as stopped and started again with their data intact.
This release also adds an optional cross-zone restart path. When `enable_cross_zone_restart` is enabled in the Terraform module, a stopped dual-disk environment can fall back to a ready data snapshot in another zone if the original zone has no VM capacity.
## Infrastructure upgrade required
This release requires a Terraform module upgrade to [v2.0.3](https://github.com/gitpod-io/terraform-google-ona-runner/releases/tag/v2.0.3) ([Terraform Registry](https://registry.terraform.io/modules/gitpod-io/ona-runner/google/latest)).
Key infrastructure changes:
* The runner custom role now includes disk label, disk update, disk snapshot, snapshot cleanup, snapshot read, and autoscaler list permissions used by dual-disk recovery and warm-pool cleanup.
* The root module and `examples/runner-with-networking` wrapper include an optional `enable_cross_zone_restart` input. The default is `false`, so existing deployments keep their current behavior unless you enable it.
* The runner VM cloud-init passes the cross-zone restart setting to the GCP runner process.
If you use pre-created service accounts or custom IAM roles, add the new permissions documented in the module release before applying the new runner version.
#### Upgrade steps
1. Update the `version` constraint in your `main.tf` module block to `v2.0.3`. See the [release page](https://github.com/gitpod-io/terraform-google-ona-runner/releases/tag/v2.0.3) for details.
2. Run `terraform init -upgrade` to fetch the new module.
3. Run `terraform plan -out=tfplan` and review the IAM and runner VM metadata changes.
4. Run `terraform apply tfplan`.
5. Optional: set `enable_cross_zone_restart = true` if you want stopped dual-disk environments to retry in another zone after a capacity error.
Full walkthrough: [Upgrade GCP runner infrastructure](/docs/ona/runners/gcp/update-runner#updating-infrastructure)
## What else is in this release
* Warm pools can use dual-disk prebuild snapshots and preserve claimed data disks for assigned environments.
* Warm-pool assignment returns sooner because the runner no longer waits for GCP label, metadata, and disk auto-delete operations to finish before reporting the claimed instance.
* Hyperdisk data disks restored from snapshots can temporarily use higher provisioned performance during hydration, then return to baseline after the GCP rate-limit window.
* Data disk discovery polls more responsively while waiting for hot-attached disks, reducing tail latency during dual-disk startup.
* GCP VM start, stop, delete, and resume failures now include enough INFO-level logging to diagnose common GCP API failures from support bundles.
* Runner request streams reconnect faster after transient backend unavailability.
* Credential proxy setup blocks less of environment startup while keeping private repository clone support available before content initialization.
* Consumed dual-disk data snapshots are cleaned up after the environment is running.
* The GCP VM image now uses updated Google guest-agent and OS Config agent builds with patched gRPC dependencies.
* VM image build components were rebuilt with patched Go toolchains, and Docker Engine was updated to 29.5.3.
* Runner Go dependencies including `golang.org/x/crypto`, `golang.org/x/net`, and `github.com/cloudflare/circl` were updated to address fixable CVEs.
## Updated VM image with Ubuntu 26.04
Environment VMs now run Ubuntu 26.04 with kernel 7.0 and Docker 29.4.3. This upgrade reduces the total CVE count from 6,731 to 275 (a 96% reduction). The remaining CVEs are in upstream binaries (NVIDIA toolkit, Google guest agent) that we do not compile.
No action is required. The new VM image is applied automatically when environments start.
## What else is in this release
* Shell command history is now synced across terminal tabs within the same environment for bash and zsh.
* Agents resume automatically when a devcontainer rebuild completes, instead of waiting for the next periodic check.
* Warm pool resume on GCP is now non-blocking. The dashboard shows environment status immediately instead of waiting up to two minutes for the VM to resume.
* Warm pool instances are claimed only when running, avoiding resume timeout failures on suspended instances.
* Data disk resize completes before content initialization in dual-disk mode, preventing out-of-space errors with large container images.
* Environments stopped by inactivity timeout are no longer restarted in a loop by the agent reconciler.
* Container service status correctly reports as stopped when the devcontainer stops, instead of showing stale running status.
* The agent reconciler now waits for devcontainer readiness during rebuilds instead of failing with connection errors.
* Bitbucket repository search and workspace listing work correctly after Bitbucket deprecated cross-workspace APIs.
* Conversation chunk reads are batched with concurrent fan-out, reducing page load latency by up to 10x.
* Upgraded OTel exporters, gRPC, go-jose (High), and jsonparser (High) to address known CVEs.
* Go bumped to 1.25.10 in VM build scripts.
* The legacy credential proxy MITM architecture has been replaced with eBPF-based request rewriting.
## Zone failover for capacity errors
If a GCP zone lacks capacity to create an environment, the runner now retries in a different zone automatically. This reduces the impact of zonal capacity exhaustion, though it does not eliminate it entirely. Runners configured with multiple zones benefit most.
## Infrastructure upgrade required
This release requires a Terraform module upgrade to [v2.0.1](https://github.com/gitpod-io/terraform-google-ona-runner/releases/tag/v2.0.1) ([Terraform Registry](https://registry.terraform.io/modules/gitpod-io/ona-runner/google/latest)).
Key infrastructure changes:
* SSH access restricted to IAP-only (port 22 no longer open to `0.0.0.0/0`).
* Shielded VM hardening enabled with Secure Boot, vTPM, and integrity monitoring. Project-wide SSH keys blocked on runner and proxy VMs.
* Flow logging added to security-critical firewall rules.
* Memory and CPU limits added to all Docker containers on the runner VM.
* TLS certificate rotation fixed for the auth proxy.
* Honeycomb API key removed from Terraform configuration and VM metadata.
* Managed metrics direct push enabled for the metrics pipeline.
#### Upgrade steps
1. Update the `version` constraint in your `main.tf` module block to `v2.0.1`. See the [release page](https://github.com/gitpod-io/terraform-google-ona-runner/releases/tag/v2.0.1) for details.
2. Run `terraform init -upgrade` to fetch the new module.
3. Run `terraform plan -out=tfplan` and review the changes, paying attention to firewall and shielded VM settings.
4. Run `terraform apply tfplan`.
Full walkthrough: [Upgrade GCP runner infrastructure](/docs/ona/runners/gcp/update-runner#updating-infrastructure)
## What else is in this release
* The Terraform module version used to provision your runner infrastructure is now displayed on the runner details page in the dashboard.
* External user IDs are now resolved for Bitbucket and GitLab auth tokens, enabling user attribution in Insights across all SCM providers.
* Environments that fail to start within 10 minutes (supervisor never connects) are now stopped automatically instead of staying in "starting" indefinitely.
* Workspace folder path is correctly reported during environment creation when dotfiles are configured.
* Supervisor retries asset downloads on SHA-256 mismatch instead of failing permanently.
* File watch self-healing works reliably under Docker-in-Docker (fuse-overlayfs) after file unlink and recreate.
* Agent conversations no longer stall silently when the model pauses mid-turn.
* Credentials (AWS keys, GitHub tokens, basic-auth URLs, bearer tokens, JWTs) are now redacted from environment status messages, on-disk state files, and process-output logs.
## Warm pools now available on GCP
[Warm pools](/docs/ona/projects/warm-pools) keep pre-initialized Compute Engine instances in a suspended state, ready to resume when you create an environment. Instead of provisioning a new VM and loading the prebuild snapshot from scratch, Ona claims a suspended instance and resumes it. Startup drops from minutes to around 10 seconds.
Enable warm pools per environment class in your project's prebuild settings. The runner dynamically scales the pool between your configured minimum and maximum based on demand, and rotates instances automatically when new prebuilds complete.
Requires an [Enterprise plan](https://ona.com/pricing). See the [warm pools documentation](/docs/ona/projects/warm-pools) for prerequisites and setup instructions.
## Infrastructure upgrade required
This release requires a Terraform module upgrade to [v2.0.0](https://github.com/gitpod-io/terraform-google-ona-runner/releases/tag/v2.0.0) to enable warm pools and apply IAM changes.
**New IAM permissions added to the runner custom role:**
| Permission | Purpose |
| ----------------------------------- | -------------------------------------------------------- |
| `compute.autoscalers.create` | Manage MIG autoscalers for dynamic warm pool scaling |
| `compute.autoscalers.delete` | Clean up autoscalers when warm pools are removed |
| `compute.autoscalers.get` | Read autoscaler state during reconciliation |
| `compute.autoscalers.update` | Adjust autoscaler targets as demand changes |
| `compute.instanceGroupManagers.use` | Required for autoscaler to manage MIG instances |
| `compute.instances.listReferrers` | Discover which MIG owns a VM during warm pool operations |
| `compute.instances.resume` | Resume suspended warm pool VMs on claim |
| `monitoring.timeSeries.create` | Publish scaling metrics that drive the autoscaler |
**IAM role binding changes:**
* The project-level `iam.serviceAccounts.actAs` and `iam.serviceAccounts.getAccessToken` permissions have been **removed** from the runner custom role.
* Instead, the runner SA is granted `roles/iam.serviceAccountUser` on three specific service accounts: `runner_sa`, `environment_vm_sa`, and `proxy_vm_sa`. This limits impersonation to only the SAs the runner attaches to instances.
* The runner assets bucket role has been elevated from `roles/storage.objectViewer` to `roles/storage.objectAdmin` to support writing managed metrics audit payloads.
**Other infrastructure changes:**
* Unused service accounts (`build_cache`, `secret_manager`, `pubsub_processor`) are removed.
* Environment UDP egress is now restricted to DNS, NTP, and QUIC.
#### Upgrade steps
1. Update the `version` constraint in your `main.tf` module block to `v2.0.0`. See the [release page](https://github.com/gitpod-io/terraform-google-ona-runner/releases/tag/v2.0.0) for details.
2. Run `terraform init -upgrade` to fetch the new module.
3. Run `terraform plan -out=tfplan` and review the changes, paying attention to IAM and firewall rule updates.
4. Run `terraform apply tfplan`.
5. If you use [pre-created service accounts](/docs/ona/runners/gcp/setup#pre-created-service-accounts), you must:
* Add the new custom role permissions listed above.
* Grant `roles/iam.serviceAccountUser` on the `runner_sa`, `environment_vm_sa`, and `proxy_vm_sa` service accounts to the runner SA.
Full walkthrough: [Upgrade GCP runner infrastructure](/docs/ona/runners/gcp/update-runner#updating-infrastructure)
## What else is in this release
* Managed metrics pipeline lets you export runner metrics via Prometheus `remote_write` for monitoring runner health, environment lifecycle, and resource utilization. Contact your account team to enable it.
* Quota and capacity errors from GCP are now surfaced as clear machine failure messages instead of generic errors.
* Automation services support a configurable readiness timeout, preventing services from hanging indefinitely when a health check never passes.
* Orphaned MIGs, autoscalers, instance templates, and warm pool instances are automatically cleaned up, preventing resource leaks.
* Environment startup is faster. Supervisor initialization steps now run concurrently, disk pre-warming prioritizes startup-critical paths, and git configuration runs in fewer round trips.
* Warm pool claim reliability is improved. The runner picks the oldest available instance, skips in-flight instances, and recovers the default network route after resuming a suspended VM.
* Async VM creation failures are now surfaced via Pub/Sub instead of silently failing.
* Log line ordering within the same timestamp is now preserved.
* The agent operations proxy is more resilient to transient connection failures.
* Prebuild snapshots no longer carry stale git identity from the prebuild executor.
* File watch self-healing works correctly when a denylisted file is unlinked and recreated inside Docker-in-Docker.
* The runner recovers gracefully from stale gitconfig lock files.
* Updated `go-jose/v4` to v4.1.4 (High severity, GHSA-78h2-9frx-2jm8).
* Updated `go.opentelemetry.io/otel/sdk` to v1.43.0 (High severity).
* Updated Node.js to v24.14.1 (High severity).
* Updated base container images and Prometheus for CVE fixes.
* Go toolchain bumped to go1.26.2 (fixes CVE-2026-27143).