# Ambient agents
Source: https://docs.akua.dev/agents/ambient-agents
Configure agents that watch workspace signals and start investigations proactively
Ambient agents are agents that can start work from workspace signals instead of waiting for a chat message. They are useful for operations teams, sellers managing customer installs, and customers who want faster incident context.
Ambient means "always available", not "always spending compute". Most ambient agents run as lightweight policies until a configured condition matches.
## What they watch
Ambient triggers can watch signals such as:
* Failed or degraded installations.
* Cluster health changes.
* Security findings.
* Quota pressure.
* Cost or usage anomalies.
* Customer-defined operational events.
When a trigger matches, Akua creates or updates an agent session with a system-origin turn. The result appears in the same dashboard and API views as user-created sessions.
Every visible ambient run should leave a compact handoff. When you open the session later, you should see what triggered the run, what the agent inspected or changed, its current conclusion, and the recommended next action. If the agent drafted a repository change request or needs approval, the session can show that as a card instead of making you search through logs.
## Typical patterns
| Pattern | Runtime | Outcome |
| ------------------- | ---------------------------------- | ------------------------------------------------------------------------ |
| Read-only triage | No retained filesystem | Summarize likely cause and evidence. |
| Operator review | Starts read-only, may request more | Draft a runbook or repository change request and ask for approval. |
| Coding change | Retained filesystem | Clone a repository, edit files, run checks, and create a change request. |
| Guarded remediation | Policy-controlled | Apply a low-risk predefined fix with audit trail. |
## Policy first
Each ambient agent should have clear boundaries:
* Which signals can trigger it.
* How often it can run.
* How repeated events are deduplicated.
* Which workspace, seller, or customer relationship scope it can observe.
* Which severity levels should wake the agent.
* Which models it can use and how much budget it can spend.
* Which resources it can read.
* Which actions require approval.
* How long sessions and filesystems are retained.
This keeps proactive automation useful without giving agents blanket access.
Ambient sessions do not need to expose every internal step to be useful. Detailed logs and artifacts can stay attached for audit and debugging, while the main session stays readable for review, approval, and handoff.
## Seller-managed operations
Sellers can use ambient agents to watch customer installs they manage. A seller support agent can notice a failed customer install, inspect the installation, compare it to existing change requests, and draft a fix for review.
The customer still owns the workspace. The agent's access follows the workspace grants and policies configured for that relationship.
## Related topics
Add ambient triggers to a reusable agent identity.
Keep proactive work constrained and reviewable.
# Agents API
Source: https://docs.akua.dev/agents/api
Public API resources for creating sessions, submitting turns, streaming events, and resolving approvals
The Agents API is designed as a set of flat, workspace-scoped resources. Use the generated API reference for endpoint parameters, request bodies, response schemas, and try-it examples. This page explains how the resources fit together.
## API reference
Create and manage durable agent configurations.
Start, list, retain, archive, and detect conflicts for task sessions.
Submit work, inspect results, cancel turns, and emit events.
Read and stream agent progress, widgets, and artifacts.
Browse curated starting points for common agent workflows.
Read and update communication defaults and learning-mode settings.
List and resolve human approval gates.
Review and accept agent-prepared repository changes.
Workspace-scoped requests resolve the workspace from your credential — implied by a workspace API token, or selected with the optional `Akua-Context` header for broad credentials.
## SDK shape
The generated SDK groups methods by OpenAPI operation ID, not by URL nesting. A TypeScript client should read naturally:
```ts TypeScript theme={null}
const agent = await client.agents.create({
name: 'Production deploy triage',
capabilities: ['CHAT', 'CODING', 'AMBIENT']
});
const templates = await client.agentTemplates.list();
const failedInstallTriage = templates.data.find(
(template) => template.id === 'agtpl_failedinstalltriage01'
);
const session = await client.agentSessions.create({
agent_id: agent.id
});
const turn = await client.agentTurns.create(
{
session_id: session.id,
message:
'Investigate the failed production install and draft a repository change request if needed.'
},
{ idempotencyKey: 'turn-2026-05-13-prod-failure' }
);
for await (const event of client.agentEvents.stream({ turn: turn.id })) {
if (event.type === 'widget.created') {
renderAgentWidget(event.data.widget_type, event.data);
continue;
}
console.log(event.type, event.data);
}
```
## Why flat paths
The API does not use `/v1/agent/...` or deeply nested paths. Flat resources make common workspace queries easier:
* List all running turns in a workspace.
* Show every pending approval request.
* Stream events for a session or turn.
* Render dashboard chat widgets from normalized events.
* Reuse a session when an ambient trigger continues existing work.
* Inspect repository change requests across agents to avoid duplicate work.
OpenAPI tags and documentation pages provide the product grouping users expect, while the URLs stay stable and resource-oriented.
## Protocol compatibility
Akua supports Agent Client Protocol as a compatibility adapter, not as a separate product data model. The ACP bridge maps session creation, prompts, streaming updates, and permission prompts to the same `agent_sessions`, `agent_turns`, `agent_events`, and `approval_requests` resources.
Use the REST API when you need workspace-scoped management, SDK resources, list filters, audit history, quotas, billing controls, retention, or ambient agent configuration. Use ACP when an editor or agent client wants a standard interactive protocol for talking to an Akua-hosted agent.
ACP compatibility should not force Akua to copy protocol details before they stabilize. ACP currently centers on sessions, prompt turns, updates, tool calls, plans, permissions, and capability negotiation. Multi-agent and forked-session work is still evolving, so Akua keeps canonical lineage in its own resources and maps to ACP where a client supports it.
The bridge is intentionally stateless. It does not create ACP-only canonical rows, ACP IDs, or a separate approval table. Unknown ACP features are ignored when they are advisory, or represented as `agent_events` artifacts when the information should remain visible in the dashboard and event stream.
Zed's external-agent model is a useful comparison. Zed uses ACP to connect external agents to the editor UI, but external agents still keep their own authentication, billing relationship, configuration files, and feature limits. Akua follows the same separation: ACP is an adapter for interactive agent clients, while Akua resources own workspace scope, approvals, repository change requests, quotas, retention, and audit history.
ACP permission prompts and Codex-style approvals are runtime gates. Akua maps them into `approval_requests` so they can be listed, audited, expired, and resolved from the dashboard or API. Repository change requests stay separate: they are durable change artifacts with diffs, validation, and review state. Accepting one can itself require an approval request when policy demands it.
## Integration examples
Use the REST API or generated SDK for durable product integration. Use Code Mode/MCP when an agent needs to discover and call the Akua API as a tool. Use ACP when an editor or agent client already speaks the protocol and wants a standard interactive stream.
```ts TypeScript SDK theme={null}
const approvals = await client.approvalRequests.list({
state: 'PENDING',
agent: agent.id
});
await client.approvalRequests.resolve(
approvals.data[0].id,
{ decision: 'APPROVE' },
{
idempotencyKey: 'approve-prod-fix-001',
ifMatch: approvals.data[0].etag
}
);
```
```js Code Mode theme={null}
const res = await platform.request('/v1/repository_change_requests?state=READY', {
headers: { 'Akua-Context': 'ws_123' }
});
const body = await res.json();
return body.data.map((change) => ({
id: change.id,
parent_repository_id: change.parent_repository_id,
state: change.state
}));
```
```json ACP theme={null}
{
"method": "session/prompt",
"params": {
"message": "Investigate the failed install and ask before accepting any change."
}
}
```
## Schema notes
Some fields are intentionally split so clients can distinguish preferences from policy-controlled results:
| Field | Resource | Meaning |
| ------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------- |
| `communication_profile` | Session | Resolved active profile for beginner, intermediate, advanced, expert, or adaptive language. |
| `runtime_hint` | Turn | Client preference such as `AUTO`, `CODE_MODE`, or `RETAINED_RUNTIME`. |
| `runtime_decision` | Turn | Whether the runtime request was allowed, denied, or requires approval. |
| `resolved_execution_mode` | Turn | What Akua actually used after applying agent policy and workspace limits. |
| `origin` | Session and turn | Where the work came from: dashboard, API, MCP, ACP, ambient, or system. |
| `usage_summary` | Agent, session, and turn | Provider cost, runtime compute, storage, MCP/API calls, and ambient trigger counts when populated. |
| `agent_turn_id` | Snippet and snippet run | Optional attribution for session-scoped generated snippets and prepared actions. |
Widget events should be typed. A `widget.created` event carries `widget_type`, `schema_version`, `resource_refs`, optional `reactive_bindings`, and `actions`. Initial widget types include `approval_card`, `choice_card`, `status_card`, `navigation_hint`, and `repository_change_request_review`.
Actions are prepared platform actions, not arbitrary client code. Reactive bindings let dashboard widgets stay current while API and ACP clients can ignore them or render their own equivalents.
Widgets may represent a whole interaction, not just one resource. For example, an agent can emit a card that combines a repository change request, an install status, a documentation link, and prepared reply buttons. Akua can also synthesize default widgets from canonical resources; resource state remains the source of truth.
V1 does not need a separate widget-action endpoint. Clients execute the underlying action through the canonical resource API, such as resolving an approval request, creating a turn, submitting structured input, running an attributed snippet action, or navigating to a dashboard path. Attributed snippet runs roll up to the source turn's `usage_summary.api_call_count`.
## Idempotency and state
Mutation requests that create work use `Idempotency-Key` so clients can safely retry interrupted requests. Mutable resources include `etag` and use `If-Match` when an update depends on the current state.
Clients should not set lifecycle state directly. Use resource actions such as cancel a turn, resolve an approval request, or archive a session.
## Related topics
Authenticate API clients and set workspace scope.
Jump into the generated endpoint reference.
Let external agents call the API through Code Mode.
Understand grants, approvals, and audit events.
# Communication style
Source: https://docs.akua.dev/agents/communication
How agents adapt explanations, vocabulary, and detail level to each user
Agents should feel like a senior colleague who knows when to explain and when to move quickly. A new developer should not have to understand Kubernetes vocabulary before deploying an app. A platform engineer should not have to read beginner explanations before getting to the diagnosis.
## Proficiency profiles
| Profile | Best for | How the agent speaks |
| ------------ | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| Beginner | Developers who have shipped code but not operated infrastructure | Everyday language, one step at a time, UI prompts before actions. |
| Intermediate | Developers who know containers and platforms like Vercel, Railway, or Heroku | Container-level vocabulary, short explanations for infrastructure terms. |
| Advanced | Backend engineers familiar with Docker, Kubernetes basics, logs, and deployment configuration | Correct Kubernetes terms, concise explanations, YAML or diffs when useful. |
| Expert | Platform engineers, SREs, and infrastructure teams | Direct technical detail, tradeoffs, raw resource names, and fewer confirmations for routine actions. |
Users should be able to change this at any time with a control such as **Talk to me as: Beginner / Intermediate / Advanced / Expert**. The agent should not silently change someone's level based on writing style.
Akua should remember the user's default per workspace. A session can override it for a single conversation, and the active style is stored on the session.
The profile changes presentation, not reasoning quality. The agent should still inspect the same logs, events, repository change requests, resources, and evidence. Beginner mode should put the plain-language summary first, while keeping technical details available. Expert mode should surface the technical detail immediately.
## Same issue, different language
Each example below describes the same diagnosis. Only the explanation changes; the underlying evidence stays the same.
```text theme={null}
Agent: Found it. Your app is trying to use a database, but no database is
connected yet.
I can set one up and connect it for you. It should take about a minute.
[Approval: Set up database] [Not now]
```
```text theme={null}
Agent: Your container exits because DATABASE_URL is missing. I can create a
Postgres instance and inject the connection string, or you can provide an
existing database URL.
[Create Postgres] [Use existing database]
```
```text theme={null}
Agent: Pod is in CrashLoopBackOff. Last log line:
Error: connect ECONNREFUSED 127.0.0.1:5432
The app expects Postgres on localhost, but no database runs in the pod.
Use a Secret-backed DATABASE_URL or deploy Postgres separately.
[Create repository change request]
```
```text theme={null}
Agent: CrashLoopBackOff caused by DB connection to 127.0.0.1:5432.
No sidecar or local Postgres present. Recommend Secret-backed DATABASE_URL
and readiness gate after migration check.
I can patch values and create a repository change request.
```
## Learning mode
Learning mode is separate from proficiency. When enabled, the agent adds short, expandable explanations for concepts the user has not seen before.
```text Example theme={null}
Agent: I’ll start your app on one of your servers.
Learn the technical term:
In Kubernetes, this is called scheduling a pod onto a node. A pod is the running
copy of your app, and a node is a server in your cluster.
```
Learning notes should not repeat forever. Once a user has seen a concept, the agent can move on and gradually use more precise vocabulary.
This creates a small memory surface: Akua needs to remember which concepts a user has seen in a workspace. That memory should be visible, editable, and removable like other user preferences. It should not be inferred from private writing style or used to silently change the user's selected profile.
## Vocabulary mapping
| Concept | Beginner | Intermediate | Advanced | Expert |
| ---------------- | ------------------------------- | ---------------------- | -------------------- | ---------------------------------- |
| Cluster | your group of servers | your cluster | cluster | cluster |
| Pod | your running app | your container | pod | pod |
| Deployment | your app | your deployment | Deployment | Deployment |
| Namespace | project space | namespace | namespace | namespace |
| Helm chart | app installer | app package | Helm chart | Helm chart |
| Secret | stored password | secret | Secret | Secret |
| Liveness probe | health check | health check | liveness probe | liveness probe |
| CrashLoopBackOff | your app keeps crashing | container restart loop | CrashLoopBackOff | CrashLoopBackOff |
| ImagePullBackOff | could not download your app | image pull error | ImagePullBackOff | ImagePullBackOff |
| Rollback | go back to the previous version | roll back | rollback to revision | shift traffic to previous revision |
## Related topics
See realistic deployment, investigation, and compute recommendation flows.
Set communication style, runtime policy, grants, and triggers.
# Configure an agent
Source: https://docs.akua.dev/agents/configure
Define an agent with skills, model policy, runtime policy, grants, and optional ambient triggers
Create an agent when you want a reusable automation identity for a workspace. A production triage agent, a repository-change agent, and a seller support agent can all use the same resource model with different instructions and policies.
Agent resources are available through the API. Dashboard configuration screens will expose the same fields as product UI.
## What you configure
| Setting | Purpose |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name and description** | Helps users choose the right agent. |
| **Instructions** | Defines the agent's role and operating style. |
| **Skills** | Adds reusable behavior such as repository change triage or deployment investigation. |
| **Capabilities** | Enables broad modes such as chat, coding, and ambient operation. |
| **Communication style** | Controls whether the agent explains work in beginner, intermediate, advanced, expert, or adaptive language. See [Communication style](/agents/communication). |
| **Model policy** | Controls model selection, budget, and whether provider billing is Akua-managed or workspace BYOK. |
| **Runtime policy** | Defines when the agent can use a retained runtime, filesystem, shell, or browser. |
| **Grants** | Limits which platform resources the agent can read or mutate. |
| **Permission policy** | Decides which actions require human approval. |
| **Ambient triggers** | Starts work automatically when configured signals match. |
## Grants
Grants are explicit permissions. Avoid giving an agent broad mutation access when it only needs context.
For agents that prepare repository change requests, the recommended baseline is:
| Resource | Actions | Why |
| --------------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `repository_change_request` | `read`, `create`, `continue` | Read existing change requests, create a reviewable draft, or continue a prior change request when appropriate. |
| `install` | `read` | Inspect installation state and source configuration. |
| `cluster` | `read` | Gather operational context. |
| `product` | `read` | Understand the packaged software and versions. |
Additional actions such as update, close, or accept should be separate grants and can require approval.
## Model policy
Agents can use Akua-managed billing or workspace-owned provider credentials. Workspace credentials are referenced through secrets; secret values are not exposed to the agent runtime.
Use budget limits for agents that can run automatically or launch coding work.
## Communication style
Agents should match the user's experience level. A beginner may need "your app keeps restarting" with a suggested next step. An expert may prefer exact resource names, recent events, and the underlying Kubernetes status.
Use an adaptive style when the agent should vary detail within an explicit user, session, or agent default. The agent should not silently change a user's proficiency level based on writing style.
Communication style should not reduce analysis quality. It changes how findings are explained, not what evidence the agent gathers or records.
## Runtime policy
Not every task needs a retained runtime. Prefer the cheapest safe runtime:
| Runtime need | Use |
| --------------------------------- | --------------------------------------- |
| Read platform state and summarize | No retained runtime |
| Call Akua API through tools | No retained runtime |
| Edit a repository or run tests | Retained filesystem |
| Run commands | Shell, usually approval-gated |
| Inspect a web app visually | Browser, usually disabled unless needed |
## Related topics
Configure background triggers and policy.
Choose safe grants and approval gates.
# Agent dashboard
Source: https://docs.akua.dev/agents/dashboard
Configure ambient agents and interpret agent-generated widgets in the Akua dashboard
The dashboard is the primary managed experience for hosted agents. It gives users a chat surface, approval inbox, event history, and resource-aware widgets without requiring local agent setup.
The managed dashboard experience is rolling out in phases. API resources and generated reference docs are available while some dashboard controls may appear only for enabled workspaces.
## Configure ambient agents
Ambient agents start from workspace signals instead of a chat message. Configure them when you want Akua to investigate operational signals proactively.
Start from a platform template such as failed-install triage, or create a workspace agent with the skills and grants it needs.
Turn on ambient operation for the agent and choose the signals it can receive.
Pick trigger types such as install failure, degraded cluster, security finding, quota pressure, or cost anomaly. Set a minimum severity and cooldown so repeated signals do not create noisy duplicate work.
Prefer read-only triage by default. Allow retained runtimes only when the agent may need repository edits, tests, or package-manager work.
Give read grants for resources the agent needs to inspect. Keep mutation grants specific, and require approval for sensitive actions such as accepting repository change requests or accessing secrets.
An ambient run should always leave a reviewable summary in its session. The summary explains the trigger, inspected resources, conclusion, next action, and links to related resources.
## Interpret widgets
Agents can emit typed widgets into the dashboard event stream. Widgets are not separate state stores; they are views over canonical resources such as approval requests, repository change requests, installs, renders, operations, snippets, and documentation links.
| Widget | What it means |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Approval card | The agent is waiting for a runtime-gated action, such as running a command or accepting a change. |
| Choice card | The agent needs a structured decision before it continues. |
| Status card | The agent is summarizing resource state, progress, or a completed investigation. |
| Navigation hint | The agent found a relevant dashboard area and can take you there. |
| Repository change request review | A fork-backed source/config change is ready to inspect, accept, reject, or withdraw. |
| Secret input | The agent needs a credential reference and should route you through the secret flow instead of seeing raw secret values. |
Widgets may combine multiple resources. For example, a failed-install widget can show the install, recent render, existing repository change request, and prepared next actions in one place.
## Reactive state
Widgets should stay current from canonical resource state. If a repository change request moves from `READY` to `ACCEPTING`, the widget updates from that resource state instead of relying on stale assistant text.
When a widget includes an action, the action calls the underlying resource API. Examples:
* Resolve an approval request.
* Start a new agent turn with a prepared reply.
* Create or accept a repository change request.
* Run an attributed snippet action.
* Navigate to an install, render, operation, cluster, or repository.
This keeps dashboard behavior, API behavior, and agent behavior aligned.
## Related topics
Understand ambient trigger concepts and policy boundaries.
Use the same resources from the API.
# Examples
Source: https://docs.akua.dev/agents/examples
Concrete examples of how hosted agents can guide deployment, infrastructure choices, investigations, and reviewable changes
These examples show the intended feel of hosted agents: a user describes an outcome, the agent gathers context, uses the right tools, and turns the result into a reviewable next step. Some examples combine API resources that are available now with dashboard experiences that are still being productized.
## Deploy a repository
`Deploy github.com/acme/helpdesk to staging. It needs Postgres and should be reachable at helpdesk-staging.example.com.`
It reads the project files, detects the runtime, finds required environment variables, and identifies the database dependency.
It renders a short form for the domain, environment variables, and deployment target instead of asking you to write a manifest.
It prepares the package, deployment configuration, and install changes, then asks for approval before applying anything sensitive.
```text Conversation theme={null}
You: Deploy this repository to staging.
Agent: I found a Node app with a Postgres dependency. I can create a staging install,
generate the deployment config, and set up the database connection.
[Form: deployment target, domain, missing environment variables]
Agent: I prepared a repository change request with the package config and install values.
[Approval: Create staging install]
```
## Pick cost-efficient compute
Agents can use external data tools when the decision depends on live market data. Akua's [Hetzner Value Auctions](https://auction.akua.dev/) tool indexes dedicated server auctions, CPU benchmarks, memory, disks, locations, and price so an agent can recommend hardware before a user buys it.
```text Conversation theme={null}
You: I need a cheap worker for Postgres. At least 64 GB RAM, NVMe preferred, under 50 EUR/month.
Agent: I’ll compare current auction servers against that workload.
Agent: Best fit right now:
1. 64 GB RAM, NVMe storage, strong single-thread score, under your budget.
Good fit for Postgres and small multi-tenant workloads.
2. 128 GB RAM option, slightly more expensive.
Better if you expect large indexes or want more cache headroom.
I recommend option 1 for the current workload. Want me to add it as a worker
candidate for your cluster, or save it for later review?
[Choice: Add worker candidate] [Save recommendation] [Show details]
```
The user gets a recommendation in the same deployment flow. The agent can explain the tradeoff in plain language, or show CPU models, disk layout, datacenter, hourly cost, and benchmark scores for advanced users.
## Investigate a failing install
```text Conversation theme={null}
You: Why did the customer install fail after the last update?
Agent: I’ll compare the current install, recent change request history, deployment events,
and logs.
Agent: The install started failing after the latest values change removed
DATABASE_URL from the runtime environment. There is already a stale change request that
adds it back and updates the secret reference.
[Card: Existing change request found]
[Choice: Continue change request] [Create new change request] [Only summarize]
```
This is why agents need read access to existing repository change requests. They can avoid duplicate work, continue a previous attempt, or explain why a change request should be replaced.
## Watch production signals
Ambient agents are useful when the right time to ask for help is before a human opens the chat.
```text Ambient event theme={null}
Signal: production install failed twice in 10 minutes
Agent: I started a read-only investigation for the failed production install.
Findings:
- The new version is healthy in staging.
- Production fails only in one region.
- The failing pods cannot pull the image from the private registry.
Suggested next step:
Rotate the registry token for the affected workspace and retry the rollout.
[Approval: Create repository change request] [Open install] [Dismiss]
```
The agent is always available, but it does not need to consume expensive runtime resources while waiting. It starts work only when configured signals match policy.
## Related topics
See how the same agent adapts for beginners, advanced operators, and experts.
Connect local AI tools to Akua through Code Mode.
Define skills, policies, grants, and runtime behavior.
Understand sessions, retained runtimes, model budgets, and trigger limits.
# How agents work
Source: https://docs.akua.dev/agents/how-it-works
The resource model behind Akua agents, sessions, turns, events, skills, and repository change requests
An agent is a configured identity in a workspace. It has instructions, skills, policies, grants, and optional ambient triggers. You can use the same agent from the dashboard, API, or an automated signal.
The important distinction is between the long-lived agent configuration and the work it performs.
## Dashboard-native guidance
In the dashboard, an agent is more than a text box. It can behave like an interactive guide for deployment and operations work:
* Ask clarifying questions when a request is ambiguous.
* Render approval prompts before sensitive actions.
* Show deployment progress, status cards, documentation cards, and code blocks inline.
* Link or navigate to the right dashboard page when a visual workflow is better than chat.
* Adjust its language to the user's experience level.
This lets a user describe intent, such as "deploy my app", while the agent turns that intent into structured platform actions and reviewable decisions.
## Core resources
| Resource | What it represents |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| **Agent** | The configured identity: name, instructions, skills, capabilities, policies, and grants. |
| **Skill** | A versioned behavior module that teaches an agent how to perform a class of work. |
| **Session** | A durable conversation or task thread for one agent in one workspace. |
| **Turn** | One submitted instruction and its result. |
| **Event** | A normalized stream entry: message, progress update, widget, runtime lifecycle, artifact, handoff summary, or cancellation. |
| **Approval request** | A human approval gate for actions that need review. |
Sessions are cheap to keep open. Runtime environments are only used when a task needs files, a shell, a browser, git, package managers, or long-running command execution.
## Agents are not tied to one runner
The API describes what an agent is allowed to do, not which internal runner executes it. A read-only triage agent might only call platform tools. A coding agent might use a retained workspace with repository access, command execution, package managers, and test tooling.
This keeps the public contract stable as the runtime improves.
For platform operations, agents should prefer fast structured API work. For tasks that need files, repositories, scripts, package managers, browsers, or state between turns, they can use a retained runtime. Users see one conversation either way.
## Repository change requests are the review surface
When an agent needs to change repository-backed installation source or configuration, the default path is a [repository change request](/installs/repository-change-requests). The agent reads existing change requests in the workspace, checks whether work is already in progress, and creates a new request only when needed.
This prevents duplicate work and keeps production changes reviewable. Repository change request access is controlled by grants, and accepting a change can require a separate approval request. Read access does not imply permission to accept a change.
## Sessions produce events
Every turn emits events that the dashboard and API can display:
* Messages from the user, system, or assistant.
* Progress updates for platform, git, shell, browser, or repository work.
* Interactive UI outputs such as approval cards, status cards, forms, or documentation cards.
* Runtime start, stop, and resume events.
* Artifacts such as repository change requests, diffs, summaries, logs, or files.
* Handoff summaries and cancellation events.
The event stream is the source for chat replay, audit views, and external integrations.
## Related topics
Follow the lifecycle of a task.
See how agent sessions feel in deployment and operations workflows.
Understand grants, approvals, and workspace isolation.
See how agents adapt explanations to different users.
# Agents
Source: https://docs.akua.dev/agents/index
Agents that deploy, investigate, and prepare reviewable changes with clear controls
Agents are workspace-native automation in Akua: describe the outcome, let the agent gather context, and review the proposed action before anything sensitive changes.
## Work modes
The same configured agent can help in chat, investigate platform state, use code when needed, or run from a configured signal.
Ask the dashboard sidebar to deploy a repository, explain a failed install, compare customer installs, or prepare a safe next step.
Gather evidence from platform state, install status, logs, package versions, and existing repository change requests before deciding what to do.
Use fast Code Mode for structured platform operations, then switch to a retained runtime when the task needs files, git, package managers, command execution, or tests.
Watch configured signals and start an investigation when deploy failures, security findings, quota pressure, or cost anomalies match policy.
Agents are clients of the same Akua API used by the dashboard, CLI, and MCP server. That keeps behavior auditable and avoids separate automation paths.
## Why agents matter
Agents turn deployment and operations work into a guided conversation. The embedded dashboard agent is the managed path: no local setup, shared workspace context, and review controls built into the UI.
Tell the agent what you want to run. It can identify setup steps, ask for missing configuration, and show deployment progress.
Sensitive actions use repository change requests, approval requests, and audit events instead of invisible automation.
Beginners get plain-language guidance. Experts get concise technical detail, exact resource names, and direct controls.
Codex, Claude Code, and other MCP-compatible clients can connect through the Platform MCP server when teams prefer local workflows.
## Product model
Understand agents, skills, sessions, turns, events, and repository change requests.
See realistic deployment, investigation, compute recommendation, and ambient flows.
Create agents, sessions, turns, approvals, and repository change requests.
Understand beginner, intermediate, advanced, and expert agent responses.
Define instructions, skills, model policy, runtime policy, grants, and triggers.
Configure ambient agents and understand widgets in the managed UI.
See how a conversation or task progresses over time.
Configure agents that respond to deploy failures, degraded clusters, findings, and other signals.
Control what agents can read, prepare, execute, and accept.
Build on the public API resources and SDK shape.
Understand agent sessions, retained runtimes, model budgets, and trigger limits.
Triage stuck sessions, sandboxes, provider outages, triggers, and cleanup.
## When to use an agent
Use an agent when the work benefits from platform context, repeatability, or review:
| Use case | Good fit |
| ------------------------------- | -------------------------------------------------- |
| Explain a failed installation | Read-only triage agent |
| Compare two installations | Chat or API-created session |
| Create a reviewable fix | Coding agent with repository change request access |
| Watch production failures | Ambient agent with deploy-failure triggers |
| Run a safe low-risk remediation | Agent with explicit pre-approved grants |
For direct API exploration without a hosted session, use the [Platform MCP server](/ai/platform-mcp). For repository-focused design, see [Agents and installation repositories](/ai/repo-agents).
## Common questions
No. Sessions are cheap to keep open, but retained runtimes only start when work needs files, commands, a browser, or repository access. Ambient agents wait on configured signals until a condition matches.
The default path is a repository change request. Accepting a change requires separate grants and can require explicit approval at runtime.
Yes. Agents support Akua-managed billing and workspace-owned provider credentials through workspace secrets. Secret values are not exposed to the agent runtime.
Retained filesystems expire according to workspace policy unless pinned. Summaries, repository change requests, and audit events are cheaper to keep than full runtime state.
## Related topics
Let external AI tools call Akua through Code Mode.
See how hosted agents guide installs, machine choices, and investigations.
The git-backed installation surface agents inspect and propose changes against.
How agents use repositories and change requests for reviewable changes.
Pricing and limits for sessions, turns, retained runtimes, and provider usage.
# Limits and pricing
Source: https://docs.akua.dev/agents/limits
Which limits and billing controls apply to hosted agents, retained runtimes, and provider usage
Hosted agents use the same workspace boundary as the rest of Akua. Sessions are cheap to keep open, but model usage, retained runtimes, filesystem storage, and automated triggers need explicit limits.
## Limits that apply to agents
| Limit | Scope | Canonical source |
| --------------------- | ------------------------------------ | -------------------------------------------------------------------- |
| Active agent sessions | Workspace quota | [Quotas →](/platform/quotas) |
| Running turns | Workspace concurrency limit | [Quotas → Concurrency limits →](/platform/quotas#concurrency-limits) |
| Retained runtimes | Workspace quota and retention policy | [Sessions and turns →](/agents/sessions-and-turns#retention) |
| Provider usage | Model budget and rate limit | [Configure an agent →](/agents/configure#model-policy) |
| API and MCP calls | Rate limit | [Quotas → Rate limits →](/platform/quotas#rate-limits) |
| Ambient triggers | Workspace policy and cooldown | [Ambient agents →](/agents/ambient-agents) |
Agent limits use per-workspace admission control before expensive work starts, so an agent cannot silently exceed runtime, provider, or automation limits.
When a limit blocks work before a turn is accepted, the API should return a structured error and create no turn. If work was accepted but a later runtime or budget gate blocks progress, the turn should expose a structured admission error that names the limit, scope, current usage, maximum, and retry timing when a retry is useful. Usage summaries should separate provider cost, retained runtime compute, retained filesystem storage, API/MCP calls, and ambient trigger runs.
## Pricing model
Agents support two billing paths:
| Billing path | How it works |
| -------------------- | ------------------------------------------------------------------------------------------- |
| Akua-managed billing | Akua routes provider calls and charges usage according to the workspace plan. |
| Workspace BYOK | The workspace supplies provider credentials through secrets and pays the provider directly. |
Retained runtimes are separate from model usage. A long-running coding task can consume compute, storage, and provider budget, while a read-only triage turn may only use platform tools and a small model budget.
## Usage dimensions
Agent usage is reported separately so teams can see what drove cost or limits:
| Dimension | What it measures |
| ---------------- | -------------------------------------------------------------------------------- |
| Provider tokens | Tokens sent to and returned from model providers. |
| Provider spend | Provider cost attributed to the workspace, agent, session, and turn. |
| Runtime compute | Seconds a retained sandbox spent running compute. |
| Retained storage | GB-hours for retained session filesystems. |
| API calls | Attributed platform API calls made by generated widgets, snippets, or Code Mode. |
| MCP calls | Tool calls made through MCP/Code Mode bridges. |
| Ambient triggers | Signal-triggered runs admitted by ambient policy. |
## Cost controls
Use agent policy to keep spend predictable:
* Set model budgets for agents that run automatically.
* Prefer Code Mode for platform operations that do not need files or shell access.
* Start retained runtimes only when repository, package manager, browser, or test work is required.
* Use cooldowns for ambient triggers.
* Expire retained filesystems unless the session is pinned.
* Require approval before shell commands, network egress, repository change request acceptance, or secret access.
Platform plans and included limits.
How resource, concurrency, and rate limits work.
Set model policy, runtime policy, grants, and triggers.
Review approvals, grants, and audit behavior.
# Permissions and security
Source: https://docs.akua.dev/agents/permissions-and-security
How Akua keeps agent work scoped, reviewable, and auditable
Agents operate inside a workspace boundary. They do not receive unrestricted credentials, and they do not bypass the same controls used by the dashboard, CLI, and API.
## Workspace boundary
Workspace membership, roles, quotas, and billing apply to agent work. If a user or integration cannot access a workspace resource, an agent running for that user or policy should not access it either.
Agents should receive the smallest useful grants for their job. Read access is separate from mutation access.
## Grants and approvals
Grants define what an agent is allowed to attempt. Approval requests decide which sensitive actions require a human decision at runtime.
Approval requests map cleanly to ACP permission prompts and Codex-style approvals, but Akua keeps them as durable workspace resources so they can be listed, audited, expired, and resolved from the dashboard or API.
Approvals are not [repository change requests](/installs/repository-change-requests). An approval request answers "may this action proceed now?" A repository change request is the durable change artifact: the diff, validation status, review comments, and accept lifecycle. Agents can create or continue change requests without being allowed to accept them.
Examples:
| Action | Recommended handling |
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| Read installs, clusters, products, and repository change requests | Grant directly when the agent needs operational context. |
| Create a repository change request | Grant to change-preparing agents; the change is still reviewable. |
| Continue an existing repository change request | Grant separately when the agent may attach work to a previous change request or fork. |
| Accept a repository change request | Require explicit grant and approval. |
| Run shell commands | Require approval unless the command comes from a tightly controlled automation path. |
| Use network egress | Deny by default and approve only when needed. |
| Access secrets | Do not expose secret values to the agent; route access through approved platform actions. |
## Repository change access
Agents should be allowed to read existing workspace repository change requests when granted. That lets them avoid duplicate work, continue a stale change request, or reuse a fork repository.
Reading change requests does not mean the agent can change or accept them. Mutation actions are separate grants and can be approval-gated.
## Provider credentials
Hosted agents call model providers through Akua-controlled routing. The agent runtime sees local provider endpoints and placeholder tokens; real provider credentials are injected outside the agent runtime.
Workspaces can use Akua-managed billing or bring their own provider credentials through workspace secrets. Secret values are not written into agent instructions, events, or retained filesystems.
Provider routing is also the accounting boundary. Each hosted provider request is attributed to the workspace, agent, session, and turn before usage rolls up into budgets and rate limits. Redaction runs before provider metadata is exposed in events or transcript views.
## BYOK
Bring-your-own-key mode references workspace secrets by ID. Agents do not receive the raw key. If a credential is disabled, rotated, or missing an enabled version, provider requests should fail before the runtime receives useful access.
Use BYOK when your workspace needs its own provider account, billing relationship, data policy, or model allowlist. Use Akua-managed billing when you want the platform to manage provider credentials and enforce workspace budgets centrally.
## Sandbox isolation
Retained runtimes are separate from the Akua control plane. They run with a workspace-scoped session directory and a constrained service identity.
Hosted coding sandboxes should not receive management-cluster credentials, long-lived git credentials, provider keys, or production service secrets. They should use scoped repository tokens, local provider endpoints, and the Akua API/MCP configuration prepared for the current session.
Production sandboxes use additional isolation such as a sandbox node pool, network policy, gVisor runtime isolation, dropped Linux capabilities, and no host-level mounts. If a task does not need files, commands, package managers, or a browser, prefer Code Mode or structured API tools instead of starting a retained runtime.
## Prompt-injection boundaries
Agents inspect user repositories, logs, and generated files. Treat all of that content as untrusted input.
Important boundaries:
* Repository files can guide diagnosis, but they do not grant permission to call APIs, reveal secrets, or accept changes.
* Logs and provider responses can be summarized, but secrets and credential-shaped strings are redacted before storage.
* Dashboard widgets can prepare API calls, but the canonical resource API still validates grants, idempotency, `If-Match`, workspace scope, and approval state.
* Instructions from platform skills and generated sandbox `AGENTS.md` define the safety rules the harness should follow during code work.
## Auditability
Agent work emits events for messages, tool calls, approval requests, approvals, usage, artifacts, and terminal results. These events give users a timeline they can inspect later.
For changes to installs, repository change requests and git history are the durable record. Full chat transcripts and retained filesystems should expire according to workspace policy unless pinned.
## Retention
Keep durable decision records longer than raw runtime state. Repository change requests, git commits, approval decisions, summaries, and audit events are usually cheaper and safer to retain than full transcripts, provider payloads, and retained filesystems.
Retention policy should distinguish:
* Session and event history.
* Provider exchange metadata.
* Artifacts and summaries.
* Approval requests and decisions.
* Repository change requests and git forks.
* Retained runtime filesystems.
## Related topics
See how work is tracked and streamed.
Review limits that protect workspace spend and runtime usage.
The reviewed-proposal surface agents use to change installs.
# Agent runbooks
Source: https://docs.akua.dev/agents/runbooks
Operational checks for stuck sessions, stuck sandboxes, provider outages, runaway triggers, and retained filesystem cleanup
Use these runbooks when an agent workflow is slow, stuck, noisy, or blocked by infrastructure. Start from the workspace, agent, session, turn, and operation IDs visible in the dashboard or API response.
## Stuck session
Symptoms:
* A session stays active but no new events arrive.
* A submitted turn is queued longer than expected.
* The dashboard reconnects but shows no state change.
Checks:
1. Get the session and latest turns with `GET /v1/agent_sessions/{id}` and `GET /v1/agent_turns?session=...`.
2. Stream events with `GET /v1/agent_events:stream?session=...` to confirm whether the event cursor is advancing.
3. Check for pending approvals with `GET /v1/approval_requests?session=...&state=PENDING`.
4. If the turn is blocked by quota or runtime policy, surface the admission error to the user instead of retrying blindly.
## Stuck sandbox
Symptoms:
* A turn requires a retained runtime, but the runtime does not become active.
* A retained filesystem exists, but resume does not complete.
* A sandbox stays in `CREATING`, `STARTING`, `STOPPING`, or `DELETING` past its expected deadline.
Checks:
1. Inspect the turn's `runtime_decision` and `resolved_execution_mode`.
2. Check the sandbox state and last update time in the internal runtime view or operations dashboard.
3. Confirm workspace sandbox quota and retained PVC quota are not exhausted.
4. If a sandbox is stuck deleting, run the cleanup workflow rather than manually removing PVCs unless the retention policy explicitly allows it.
## Provider outage
Symptoms:
* Provider requests fail with repeated upstream errors.
* Turns fail before producing useful assistant output.
* Provider spend or token counters stop updating while requests continue.
Checks:
1. Check provider exchange metadata for upstream error codes and response timing.
2. Confirm whether the agent uses Akua-managed billing or workspace BYOK.
3. For BYOK, verify the referenced secret exists and has an enabled version.
4. Switch model/provider only through agent policy so the decision remains auditable.
## Runaway ambient trigger
Symptoms:
* Many sessions start from the same signal.
* Ambient trigger usage spikes.
* Users see duplicate investigations for one resource.
Checks:
1. Check the agent's trigger severity threshold and cooldown.
2. Search active sessions for the same resource reference before starting new work.
3. Disable the trigger or raise the minimum severity while investigating.
4. Review the trigger source for repeated identical events.
## Retained filesystem cleanup
Symptoms:
* Retained storage grows unexpectedly.
* Old sessions still have resumable filesystems.
* PVC cleanup reports failures.
Checks:
1. Check whether the session is pinned.
2. Confirm the workspace tier and retention policy.
3. Prefer the retained cleanup workflow so state transitions, audit events, and quota counters stay consistent.
4. Keep summaries, repository change requests, and git history before deleting expensive runtime state.
## Related topics
Understand quotas and usage dimensions.
Understand runtime decisions and retained filesystem behavior.
# Sessions and turns
Source: https://docs.akua.dev/agents/sessions-and-turns
How agent work is submitted, streamed, approved, cancelled, and retained
A session is a durable thread for one agent. A turn is one piece of submitted work inside that session.
This model keeps long-running work understandable: users can reopen a session, inspect previous turns, stream current events, and see what the agent is waiting for.
## Lifecycle
A dashboard chat, API client, or ambient trigger creates a session for an agent. Existing sessions can be reused when the work is a continuation.
A user or system signal sends an instruction. The turn starts in a queued or running state.
The agent emits messages, tool calls, interactive UI outputs, approval requests, artifacts, and status updates.
If the agent requests a gated action, a user approves or rejects the approval request.
The turn completes, fails, or is cancelled. Results stay visible according to workspace retention policy.
## Session states
| State | Meaning |
| ------------------------ | ------------------------------------------------------------------------- |
| `ACTIVE` | The session can accept turns. |
| `WAITING_FOR_INPUT` | The agent is done for now and waiting for the next instruction. |
| `WAITING_FOR_PERMISSION` | The agent needs a human decision before continuing. |
| `COMPLETED` | The session reached a terminal outcome. |
| `FAILED` | The session failed and may need review. |
| `CANCELLED` | Work was cancelled. |
| `ARCHIVED` | The session is hidden from active views but retained according to policy. |
## Event stream
Events are normalized across agent runners, so UI and API clients do not need to understand each internal tool.
| Event | What users see |
| -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `message.created` | A user, assistant, or system message. |
| `widget.created` | A typed approval card, choice card, form, status card, documentation card, diagram, or navigation helper. |
| `progress.updated` | The agent reports progress for a task, investigation, or prepared action. |
| `execution_environment.started` / `execution_environment.resumed` | A retained runtime started or resumed. |
| `execution_environment.stopped` / `execution_environment.deleted` / `execution_environment.failed` | A retained runtime stopped, was deleted, or failed. |
| `artifact.created` | A repository change request, diff, summary, log bundle, or file was produced. |
| `handoff_summary.created` | The agent produced a compact summary for a continuation or handoff. |
| `turn.cancelled` | The turn was cancelled. |
Widget events can include prepared actions and reactive bindings. That lets a dashboard approval card, repository change card, multi-option reply card, or status card update as the underlying resource changes, while API clients can still use the underlying approval request, repository change request, artifact, or turn state directly.
Ambient turns that appear in a user-visible session should also include a compact summary message or card before they wait or finish. The summary should make the run understandable later without replaying every event.
Turns may include a runtime hint, but Akua records the runtime decision and resolved execution mode separately. That lets a client ask for a retained runtime while policy still chooses Code Mode, denies the request, or asks for approval.
Before starting resource-scoped work, API clients can check for conflicting active sessions on the same repository, install, cluster, or repository change request. This helps avoid duplicate investigations and competing fixes.
## Retention
Session history, artifacts, and filesystems have different retention policies. Text summaries and repository change requests are cheap to keep. Retained filesystems cost more and should expire unless pinned.
Pinned sessions are useful for long investigations, customer escalations, or repository change work that should remain resumable.
## Related topics
Learn how approvals work.
Create sessions, submit turns, and stream events programmatically.
# Agent API tasks
Source: https://docs.akua.dev/agents/tasks
Create an agent, start a session, submit a turn, resolve an approval, and create a repository change request
Use these tasks when you integrate directly with the Agents API. All examples assume you have an API token and a workspace ID.
```bash theme={null}
export AKUA_API_TOKEN="..."
export AKUA_WORKSPACE_ID="ws_..."
export AKUA_API_URL="https://api.akua.dev/v1"
```
## Create an agent
Create an agent for a reusable automation identity. Keep grants narrow and add ambient triggers only when the agent should start from platform signals.
```bash theme={null}
curl "$AKUA_API_URL/agents" \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Akua-Context: $AKUA_WORKSPACE_ID" \
-H "Idempotency-Key: agent-prod-triage-001" \
-H "Content-Type: application/json" \
-d '{
"name": "Production deploy triage",
"description": "Investigates failed installs and prepares reviewable fixes.",
"capabilities": ["CHAT", "CODING", "AMBIENT"],
"grants": [
{ "resource": "install", "actions": ["read"] },
{ "resource": "cluster", "actions": ["read"] },
{ "resource": "repository_change_request", "actions": ["read", "create", "continue"] }
]
}'
```
## Start a session
Create a session when you want a durable conversation or task thread. A session can be reused across multiple turns.
```bash theme={null}
curl "$AKUA_API_URL/agent_sessions" \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Akua-Context: $AKUA_WORKSPACE_ID" \
-H "Idempotency-Key: session-prod-triage-001" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agt_...",
"origin": "API",
"title": "Investigate production install failure"
}'
```
## Submit a turn
Submit a turn to ask the agent to do work. Use a runtime hint when you know whether the task needs a retained runtime; policy still decides what runs.
```bash theme={null}
curl "$AKUA_API_URL/agent_turns" \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Akua-Context: $AKUA_WORKSPACE_ID" \
-H "Idempotency-Key: turn-prod-triage-001" \
-H "Content-Type: application/json" \
-d '{
"session_id": "ags_...",
"message": "Investigate why install inst_... failed after the latest update. Create a repository change request only if you find a likely source or config fix.",
"runtime_hint": "AUTO"
}'
```
Stream events while the turn runs:
```bash theme={null}
curl "$AKUA_API_URL/agent_events:stream?turn=atn_..." \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Akua-Context: $AKUA_WORKSPACE_ID" \
-H "Accept: text/event-stream"
```
## Resolve an approval
Approval requests are runtime gates. Resolve them with both `Idempotency-Key` and `If-Match` so retries are safe and stale approvals are rejected.
```bash theme={null}
curl "$AKUA_API_URL/approval_requests?state=PENDING&session=ags_..." \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Akua-Context: $AKUA_WORKSPACE_ID"
```
```bash theme={null}
curl "$AKUA_API_URL/approval_requests/apr_...:resolve" \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Akua-Context: $AKUA_WORKSPACE_ID" \
-H "Idempotency-Key: approve-runtime-action-001" \
-H "If-Match: 3" \
-H "Content-Type: application/json" \
-d '{ "decision": "APPROVE" }'
```
## Create a repository change request
Create a repository change request when an agent or integration needs a reviewable fork-backed change. The response returns the change request resource. Use `:create_token` to mint a scoped token for the fork.
```bash theme={null}
curl "$AKUA_API_URL/repository_change_requests" \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Akua-Context: $AKUA_WORKSPACE_ID" \
-H "Idempotency-Key: rcr-prod-fix-001" \
-H "Content-Type: application/json" \
-d '{
"parent_repository_id": "repo_...",
"change_type": "inputs_change",
"title": "Restore missing database URL",
"description": "Prepared after failed-install triage found the runtime env var was removed."
}'
```
```bash theme={null}
curl "$AKUA_API_URL/repository_change_requests/rcr_...:create_token" \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Akua-Context: $AKUA_WORKSPACE_ID" \
-H "Idempotency-Key: rcr-prod-fix-token-001" \
-H "Content-Type: application/json" \
-d '{
"scope": "write",
"expires_in_seconds": 1800
}'
```
After the fork contains commits, accept, reject, or withdraw the change request through its lifecycle actions.
## Related topics
Review the resource model and SDK shape.
Understand grants, approvals, credential proxying, and review boundaries.
# Code Mode in Action
Source: https://docs.akua.dev/ai/code-mode-in-action
See how agents compose complex multi-step operations in a single tool call
[Code Mode](/ai/platform-mcp#why-code-mode) replaces hundreds of individual MCP tools with just two: `search` and `execute`. The agent writes JavaScript that runs in a sandboxed V8 isolate. That code can fan out dozens of internal API calls, run them in parallel, aggregate results, and return a summary. All in one tool invocation.
## Why it works
LLMs have seen millions of lines of real-world JavaScript but only contrived tool-calling examples. Writing `Promise.all()` with a `.map()` is natural for them; chaining individual tool calls is not.
The sandbox provides:
* **`cnap.request()`**: typed API client with auth injected server-side
* **Full JavaScript**: `Promise.all`, `Array.map`, `Date.now()`, error handling, any logic the agent needs
* **Up to 50 API calls** per execution, enough for complex multi-step workflows
* **No network escape**: requests only reach the Akua API, never the open internet
The agent's code filters, aggregates, and formats data inside the sandbox before returning, so only the summary hits the context window, not raw API responses.
## Examples
35,000 lines across 11 pods in 506ms. Parallel fan-out with in-sandbox aggregation.
CPU/memory capacity report in 56ms. Unit parsing and computation from a single API call.
9 security checks across 7 parallel API calls, then auto-remediates with network policies.
Full SRE triage (pod health, events, error logs, rollout history), adapting at each step.
Run SQL queries, check Redis memory, and chain diagnostics, all through exec.
Compare versions, images, and CRDs across your entire fleet in one call
Discover, inspect, and interact with custom resources the agent has never seen
## What agents can do
| Prompt | What happens |
| ----------------------------------------- | ------------------------------------------------------------- |
| "Count log lines across all pods" | Parallel log fetches, line counting, sorted summary (506ms) |
| "Audit resource requests and limits" | CPU/memory unit parsing, per-pod aggregation (56ms) |
| "Audit the cluster for security" | 9 checks across pods, RBAC, secrets, network policies |
| "Create network policies for my installs" | Discovers ports, generates and applies policies per namespace |
| "Why is my app returning 500s?" | Adaptive triage: pod health → events → logs → rollout history |
| "What's the largest table in Postgres?" | Runs `psql` inside the container via exec |
| "Are my clusters on the same version?" | Parallel fan-out across all clusters, drift detection |
| "What CRDs are installed?" | Discovers custom APIs, reads schemas, queries instances |
Each row is one or two tool calls. The agent writes the code, the sandbox executes it, and only the results reach the context window.
## Related topics
How Code Mode works and the two tools it exposes.
Kube API proxy, pod logs, and command execution.
Use the same sandbox to build live operational dashboards.
The embedded dashboard agent and full agent product model.
# Dashboard Generation
Source: https://docs.akua.dev/ai/dashboard-generation
Use AI agents to generate and iterate on custom dashboards and snippets
[Custom dashboards](/dashboards/custom-dashboards) are powered by JavaScript snippets that query the Akua API (the same `cnap.request()` sandbox used by [Code Mode](/ai/platform-mcp#why-code-mode)). This makes them a natural fit for AI-driven generation: your agent already knows how to write this code.
## Why use an agent
Snippet code is an **implementation detail, not something you hand-craft**. The JavaScript is simple, repetitive, and easy to regenerate; treat it as disposable. Instead of learning API endpoints and debugging code yourself, describe what you want and let your agent handle it:
| You say | The agent does |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| "Create a dashboard showing cluster health" | Writes snippets for cluster status, KaaS version, and error counts, then creates the dashboard with all widgets |
| "Add a stat widget for total installs" | Creates a snippet that counts installs, adds it to the dashboard |
| "Make the cluster table show regions too" | Updates the snippet code to join cluster and region data |
| "The logs widget is too wide, make it half" | Adjusts the widget's column span from 4 to 2 |
The agent uses the same [Platform MCP](/ai/platform-mcp) that powers all Akua operations. It can create snippets, create dashboards, add widgets, and update layouts, all through the API.
## Workflow
Tell your agent what data matters to you. Be specific about the use case, not the implementation:
*"I want a dashboard that shows how many clusters I have, which ones are healthy, and the last 50 lines of logs from my production install."*
The agent writes the JavaScript for each widget and can test it immediately. Since snippets use the same `cnap.request()` sandbox as [Code Mode](/ai/platform-mcp#why-code-mode), the agent test-runs the code via `execute_code`, sees errors or unexpected results, fixes them, and only saves the working version as a snippet. You never see the debugging, just the finished widget.
Review the result and refine. The agent can update snippet code, change display types, resize widgets, reorder the layout, or add new widgets, all from natural language.
*"Split the cluster table into two widgets: one for KaaS clusters and one for imported."*
The dashboard is saved to your workspace. Anyone on your team can open it, and widgets auto-run on load with no setup required.
## What agents can generate
Agents can create any snippet that the Akua API supports. Common patterns:
* **Resource tables**: list clusters, installs, products, or regions with selected columns
* **KPI stats**: count resources, calculate ratios, show status values
* **Health reports**: multi-step queries that check pod status, fetch logs, and summarize issues
* **Audit views**: cross-reference installs with clusters and products for compliance or inventory
* **Log viewers**: fetch and format container logs from running pods
Since snippets can make up to 50 API calls per execution, agents can build complex multi-step widgets. For example: fetch all installs, query pods for each one, then aggregate the results into a summary table.
## Beyond platform data: application-level dashboards
Here's where it gets powerful. Snippets can use the [exec endpoint](/ai/kubernetes-access#command-execution) to run commands *inside your running containers*. Dashboards aren't limited to Akua platform data; they can reach into your actual applications.
Ask your agent to build widgets like these:
| Widget idea | What the snippet does |
| ---------------------------- | --------------------------------------------------------------------------------------------------------- |
| **Postgres table sizes** | Runs `psql` via exec to query `pg_stat_user_tables`; shows table names, row counts, and disk usage |
| **Redis memory breakdown** | Runs `redis-cli INFO memory` inside the Redis pod; displays used memory, peak memory, fragmentation ratio |
| **MongoDB collection stats** | Runs `mongosh --eval` to list collections with document counts and storage sizes |
| **Application health check** | Hits an internal `/healthz` or `/metrics` endpoint via `curl` inside the pod |
| **Queue depth** | Queries RabbitMQ or Celery via CLI to show pending/processing/failed job counts |
| **Nginx access stats** | Parses recent access logs with `awk` to show top endpoints, status code distribution, and request rates |
| **SSL certificate expiry** | Runs `openssl` to check certificate dates across services; flags anything expiring soon |
| **Disk usage per PVC** | Runs `df -h` inside pods to show persistent volume usage before you run out of space |
These are **live widgets that auto-refresh** when you open the dashboard. A single dashboard can mix platform-level data (cluster health, install status) with application-level data (database sizes, queue depths), giving you a unified view that would normally require stitching together multiple monitoring tools.
You don't need to know `psql` flags, `redis-cli` subcommands, or `mongosh` syntax. Your agent does. Just describe the data you want: *"Show me which Postgres tables are largest and whether any need vacuuming."*
## Tips
* **Let the agent debug for you**: if a widget shows an error, paste it into the conversation. The agent can test-run the snippet code via Code Mode, see exactly what failed, fix it, and update the snippet, all without you touching JavaScript.
* **Start broad, then refine**: ask for a general dashboard first, then tweak individual widgets.
* **Don't optimize the JavaScript**: if a snippet works, it's good enough. Regenerate rather than debug.
* **Use descriptive names**: tell the agent to name snippets clearly (e.g. "Cluster Health by Region" not "query1") so they're easy to reuse across dashboards.
* **Combine with Code Mode**: use [Code Mode](/ai/code-mode-in-action) for one-off investigations, then save the useful queries as snippets for ongoing monitoring.
## Related topics
Manual dashboard and snippet creation.
How the same sandbox powers AI agent operations.
Connect AI agents to Akua.
# Documentation MCP
Source: https://docs.akua.dev/ai/docs-mcp
Search and query Akua documentation in real-time from any MCP-compatible AI tool
Agents operating on Akua need context: how products work, what API endpoints are available, how to configure installs. The documentation MCP server gives them real-time access to the full Akua docs, with no authentication required.
```
https://docs.akua.dev/mcp
```
This is the **documentation** MCP server for searching docs. It does not manage your Akua resources and does not require authentication.
## What it does
* **Real-time search**: AI tools query Akua documentation as you chat, returning up-to-date answers
* **Zero configuration**: no API keys, no OAuth, no auth at all
* **Any MCP client**: works with Claude, Cursor, VS Code, and any tool that supports MCP
## Try it
Once connected, ask your AI assistant:
```text Example prompts theme={null}
How do I create a new product in Akua?
What's the difference between managed and imported clusters?
How do I set up pricing for my products?
```
The MCP server returns real-time data from the latest documentation. No stale training data.
## Other ways AI tools access docs
Beyond the MCP server, Akua provides multiple channels for AI tools:
### Contextual menu
Every documentation page includes a contextual menu with quick actions:
* **Copy page**: copy content as Markdown for pasting into AI tools
* **View as Markdown**: open the page in raw Markdown format
* **Open in AI tools**: start a conversation in ChatGPT, Claude, or Perplexity with page context
* **Connect to editors**: one-click MCP setup for Cursor or VS Code
### LLMs.txt files
Industry-standard files for AI indexing:
* **`llms.txt`**: all pages with descriptions for quick reference
* **`llms-full.txt`**: complete documentation in one file
### Markdown access
Append `.md` to any URL for AI-friendly Markdown output:
```
https://docs.akua.dev/ai/docs-mcp.md
```
## Troubleshooting
* Verify URL: `https://docs.akua.dev/mcp`
* Check internet connection
* Ensure your AI tool supports the MCP protocol
* Try the contextual menu on any doc page for automatic setup
* Check JSON syntax in config files
* Verify file permissions and correct file location
* Restart your AI application after config changes
* The MCP server always returns real-time data
* Restart the MCP connection in your tool
* Clear cached responses in your AI app
## Related topics
Learn how Akua API authentication, workspace context, and resources fit together.
Download the OpenAPI spec used by SDKs, docs, and API explorers.
Understand the product and package concepts referenced throughout the docs.
Learn how Akua places installations onto Kubernetes infrastructure.
# CRD Discovery
Source: https://docs.akua.dev/ai/examples/crd-discovery
Discover and interact with custom Kubernetes resources the agent has never seen before
Kubernetes clusters often have Custom Resource Definitions (CRDs) installed by operators, service meshes, and platform tools. These are APIs the agent has never seen in its training data. Through the kube proxy, it can discover them, read their schemas, and interact with them without any pre-built tools.
There are two ways to discover CRDs, each useful for different things.
## Approach 1: CRD API
The CRD API lists every custom resource definition installed in the cluster (names, groups, versions, and scope):
```js theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const crds = await cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/apis/apiextensions.k8s.io/v1/customresourcedefinitions`,
}).then(r => r.body);
return crds.items.map(c => ({
name: c.metadata.name,
group: c.spec.group,
kind: c.spec.names.kind,
scope: c.spec.scope,
versions: c.spec.versions.map(v => v.name),
created: c.metadata.creationTimestamp,
}));
}
```
The agent can then drill into a specific CRD to read its embedded structural schema:
```js theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const crd = await cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/apis/apiextensions.k8s.io/v1/customresourcedefinitions/ciliumnetworkpolicies.cilium.io`,
}).then(r => r.body);
// Extract the schema from the stored version
const version = crd.spec.versions.find(v => v.served && v.storage);
return {
kind: crd.spec.names.kind,
group: crd.spec.group,
version: version?.name,
schema: version?.schema?.openAPIV3Schema?.properties?.spec,
};
}
```
Best for: **"What CRDs are installed?"** Quick inventory, metadata, and embedded schemas.
## Approach 2: Kubernetes OpenAPI Spec
Since Kubernetes 1.15+, CRDs with structural schemas are included in the cluster's OpenAPI spec. The agent can fetch the full API surface (including custom resources) as proper OpenAPI paths:
```js theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const kube = (path) => cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
}).then(r => r.body);
// /openapi/v3 returns an index of all API group paths
const index = await kube("openapi/v3");
// Each CRD group has its own path, e.g. "apis/cilium.io/v2"
// Fetch a specific group to get full REST paths and schemas
const cilium = await kube("openapi/v3/apis/cilium.io/v2");
return {
available_groups: Object.keys(index.paths || {}),
cilium_paths: Object.keys(cilium.paths || {}),
};
}
```
This gives the agent the actual REST endpoints (`GET /apis/cilium.io/v2/namespaces/{ns}/ciliumnetworkpolicies`) with full request/response schemas, in the same format as the Akua OpenAPI spec it already knows how to query with `search`.
Best for: **"How do I call this custom API?"** Full REST paths, request bodies, and response schemas.
Use the CRD API for discovery ("what's installed?") and the OpenAPI spec for understanding ("how do I use it?"). An agent typically starts with the CRD API to find what's interesting, then fetches the OpenAPI group for the full schema.
## List custom resources
With the group, version, and resource name from the CRD, the agent queries instances:
```js theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const kube = (path) => cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
}).then(r => r.body);
// List all CiliumNetworkPolicies across namespaces
const policies = await kube("apis/cilium.io/v2/ciliumnetworkpolicies");
return policies.items.map(p => ({
name: p.metadata.name,
namespace: p.metadata.namespace,
endpoints: p.spec?.endpointSelector,
ingress_rules: p.spec?.ingress?.length || 0,
egress_rules: p.spec?.egress?.length || 0,
}));
}
```
## Full discovery flow
The agent can chain the whole thing: discover CRDs, pick one it hasn't seen, learn its schema, and query instances:
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const kube = (path) => cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
}).then(r => r.body);
// 1. Discover all CRDs
const crds = await kube("apis/apiextensions.k8s.io/v1/customresourcedefinitions");
// 2. Group by API group
const groups = {};
for (const crd of crds.items) {
const group = crd.spec.group;
if (!groups[group]) groups[group] = [];
groups[group].push({
kind: crd.spec.names.kind,
plural: crd.spec.names.plural,
version: crd.spec.versions.find(v => v.served)?.name,
});
}
// 3. For each group, count instances
const summary = await Promise.all(
Object.entries(groups).map(async ([group, resources]) => {
const counts = await Promise.all(
resources.map(async (r) => {
try {
const list = await kube(`apis/${group}/${r.version}/${r.plural}`);
return { kind: r.kind, count: list.items?.length || 0 };
} catch {
return { kind: r.kind, count: 0, error: true };
}
})
);
return { group, resources: counts };
})
);
return {
total_crds: crds.items.length,
groups: summary.filter(g => g.resources.some(r => r.count > 0)),
};
}
```
## Why this matters
Traditional MCP servers need a pre-built tool for every API. When a cluster has CRDs from Cilium, cert-manager, Prometheus, Argo, or any other operator, those tools don't exist. The agent is stuck.
With Code Mode + the kube proxy, the agent is self-sufficient. It discovers what's available, learns the schema, and interacts with custom resources at runtime, without any code changes to the MCP server. The API surface of the MCP grows automatically with whatever is installed in the cluster.
## Related topics
The kube proxy and exec endpoints that make this possible.
Compare CRDs, versions, and images across your entire fleet.
How the two-tool sandbox pattern works.
Connect local AI tools to Akua through Code Mode.
# Cross-Cluster Comparison
Source: https://docs.akua.dev/ai/examples/cross-cluster-comparison
Compare Kubernetes versions, images, and configurations across multiple clusters in one call
When managing multiple clusters, drift happens: different Kubernetes versions, mismatched images, inconsistent configurations. An agent can audit all clusters in parallel, comparing everything from node versions to installed CRDs.
## Version drift check
An agent asked "are my clusters running the same versions?" fans out across all clusters in a single `execute` call:
```js expandable theme={null}
async () => {
// Get all clusters
const clusters = await cnap.request({
method: "GET", path: "/v1/clusters"
}).then(r => r.body.data);
const kube = (clusterId, path) => cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
}).then(r => r.body).catch(() => null);
// Parallel fetch across all clusters
const results = await Promise.all(clusters.map(async (cluster) => {
const [nodes, version] = await Promise.all([
kube(cluster.id, "api/v1/nodes"),
kube(cluster.id, "version"),
]);
if (!nodes) return { cluster: cluster.name, status: "unreachable" };
return {
cluster: cluster.name,
k8s_version: version?.gitVersion,
nodes: nodes.items.map(n => ({
name: n.metadata.name,
kubelet: n.status.nodeInfo.kubeletVersion,
os: n.status.nodeInfo.osImage,
runtime: n.status.nodeInfo.containerRuntimeVersion,
kernel: n.status.nodeInfo.kernelVersion,
})),
};
}));
// Find drift
const versions = [...new Set(results.filter(r => r.k8s_version).map(r => r.k8s_version))];
return {
cluster_count: clusters.length,
unique_k8s_versions: versions,
drift_detected: versions.length > 1,
clusters: results,
};
}
```
## Image consistency
Compare which container images are running across clusters, catching cases where one cluster is on `v1.2.3` and another is still on `v1.1.0`:
```js expandable theme={null}
async () => {
const clusters = await cnap.request({
method: "GET", path: "/v1/clusters"
}).then(r => r.body.data);
const kube = (clusterId, path) => cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
}).then(r => r.body).catch(() => null);
const results = await Promise.all(clusters.map(async (cluster) => {
const pods = await kube(cluster.id, "api/v1/pods");
if (!pods) return { cluster: cluster.name, images: [] };
// Deduplicate images
const images = [...new Set(
pods.items.flatMap(p =>
p.spec.containers.map(c => c.image)
)
)].sort();
return { cluster: cluster.name, images };
}));
// Find images that differ across clusters
const allImages = new Map();
for (const r of results) {
for (const img of r.images) {
const name = img.split(":")[0];
if (!allImages.has(name)) allImages.set(name, new Map());
allImages.get(name).set(r.cluster, img);
}
}
const drift = [];
for (const [name, clusterVersions] of allImages) {
const tags = [...new Set(clusterVersions.values())];
if (tags.length > 1) {
drift.push({ image: name, versions: Object.fromEntries(clusterVersions) });
}
}
return { drift_count: drift.length, image_drift: drift };
}
```
## CRD comparison
Check which Custom Resource Definitions are installed in each cluster, useful for ensuring all clusters have the same operators and extensions:
```js theme={null}
async () => {
const clusters = await cnap.request({
method: "GET", path: "/v1/clusters"
}).then(r => r.body.data);
const kube = (clusterId, path) => cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
}).then(r => r.body).catch(() => null);
const results = await Promise.all(clusters.map(async (cluster) => {
const crds = await kube(cluster.id, "apis/apiextensions.k8s.io/v1/customresourcedefinitions");
return {
cluster: cluster.name,
crds: crds?.items.map(c => c.metadata.name).sort() || [],
};
}));
// Find CRDs unique to specific clusters
const allCrds = new Set(results.flatMap(r => r.crds));
const missing = [];
for (const crd of allCrds) {
const present = results.filter(r => r.crds.includes(crd)).map(r => r.cluster);
if (present.length < results.length) {
const absent = results.filter(r => !r.crds.includes(crd)).map(r => r.cluster);
missing.push({ crd, present_in: present, missing_from: absent });
}
}
return { total_unique_crds: allCrds.size, inconsistencies: missing };
}
```
## Why this matters
Multi-cluster management typically requires dedicated tools (fleet managers, policy engines, GitOps controllers). For ad-hoc checks and audits, Code Mode gives agents the same cross-cluster visibility without any additional infrastructure.
The agent uses the Akua API to list clusters, then fans out through each cluster's kube proxy in parallel. It composes the comparison logic (version matching, image diffing, CRD set intersection) inside the sandbox. One conversation, full fleet visibility.
## Related topics
Discover and interact with custom resources on a single cluster.
Audit pod security, RBAC, and network policies in one call.
The kube proxy endpoints agents use for cluster inspection.
How the parallel fan-out pattern works.
# Full-Stack Dashboard in Minutes
Source: https://docs.akua.dev/ai/examples/dashboard-in-minutes
One conversation → a live dashboard with database sizes, cache stats, app errors, and cluster health
An agent asked to *"build me a production dashboard for my SaaS"* produced a complete operational overview: Postgres table sizes, Redis memory, recent application errors, and cluster health, all as live auto-refreshing widgets. One conversation, zero config.
This is the kind of dashboard that normally means stitching together Grafana panels, writing SQL by hand, configuring Prometheus exporters, and wiring up log aggregation. Here, it's a conversation.
## The Prompt
> *"I'm running a SaaS app on Akua (Postgres for data, Redis for caching). Create a dashboard that shows me database table sizes, Redis memory, recent app errors from logs, and overall cluster health. I want to open this every morning and know if anything needs attention."*
The agent creates four snippets and assembles them into a dashboard.
## Widget 1: Postgres Table Sizes (Table)
The agent uses [exec](/ai/kubernetes-access#command-execution) to run `psql` inside the Postgres container and query `pg_stat_user_tables`:
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved from conversation
const res = await cnap.request({
method: "POST",
path: `/v1/clusters/${clusterId}:exec`,
body: {
namespace: "production",
pod: "postgres-0",
container: "postgresql",
command: ["psql", "-U", "postgres", "-t", "-A", "-F", "|", "-c", `
SELECT tablename,
pg_size_pretty(pg_total_relation_size('public.' || quote_ident(tablename))) AS total,
pg_size_pretty(pg_indexes_size(quote_ident(tablename))) AS indexes,
n_live_tup AS rows,
CASE WHEN n_dead_tup > n_live_tup * 0.1
THEN 'VACUUM NEEDED' ELSE 'ok' END AS health
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size('public.' || quote_ident(tablename)) DESC
LIMIT 10;
`]
}
});
return res.body.output.trim().split("\n").map(line => {
const [table, total, indexes, rows, health] = line.split("|");
return { table, total, indexes, rows: parseInt(rows), health };
});
}
```
Displays as a table with columns: table name, total size, index size, row count, and a health flag that warns when dead tuples exceed 10% (the table needs vacuuming).
## Widget 2: Redis Memory (Stat)
Runs `redis-cli` inside the Redis pod and extracts the key metric:
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123";
const res = await cnap.request({
method: "POST",
path: `/v1/clusters/${clusterId}:exec`,
body: {
namespace: "production",
pod: "redis-0",
container: "redis",
command: ["redis-cli", "INFO", "memory"]
}
});
const lines = res.body.output.split("\n");
const used = lines.find(l => l.startsWith("used_memory_human:"))?.split(":")[1]?.trim();
const peak = lines.find(l => l.startsWith("used_memory_peak_human:"))?.split(":")[1]?.trim();
const frag = lines.find(l => l.startsWith("mem_fragmentation_ratio:"))?.split(":")[1]?.trim();
return `${used} used / ${peak} peak (frag: ${frag})`;
}
```
Displays as a single stat: `48.23M used / 52.10M peak (frag: 1.12)`. At a glance: memory is healthy, fragmentation is low.
## Widget 3: Recent App Errors (Logs)
Fetches container logs from the application pod and filters for errors:
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123";
const kube = (path) => cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
}).then(r => r.body);
// Find the app pods
const pods = await kube("api/v1/namespaces/production/pods?labelSelector=app=web");
const lines = [];
for (const pod of pods.items.slice(0, 3)) {
const logs = await kube(
`api/v1/namespaces/production/pods/${pod.metadata.name}/log?tailLines=500`
);
const errors = logs.split("\n").filter(l =>
/error|exception|fatal|panic|timeout|5\d{2}/i.test(l)
);
lines.push(`--- ${pod.metadata.name} ---`);
lines.push(...(errors.length > 0 ? errors.slice(-10) : ["No recent errors"]));
}
return lines.join("\n");
}
```
Displays as a log viewer with syntax-highlighted output showing the last error lines from each app pod. Opens your morning with either a clean "No recent errors" or the exact lines that need attention.
## Widget 4: Cluster Health (Table)
Queries the Akua API for cluster status (no exec needed, this is platform data):
```js expandable theme={null}
async () => {
const [clusters, installs] = await Promise.all([
cnap.request({ method: "GET", path: "/v1/clusters" }).then(r => r.body.data),
cnap.request({ method: "GET", path: "/v1/installs" }).then(r => r.body.data),
]);
return clusters.map(c => {
const clusterInstalls = installs.filter(i => i.clusterId === c.id);
const healthy = clusterInstalls.filter(i => i.status === "Healthy").length;
return {
cluster: c.name,
status: c.kaas?.status ?? "imported",
version: c.kaas?.version ?? "—",
installs: `${healthy}/${clusterInstalls.length} healthy`,
};
});
}
```
Shows each cluster with its status, KaaS version, and how many of its installs are healthy. This is the infrastructure-level complement to the app-level widgets above.
## The Result
Four widgets, one dashboard, auto-refreshes on load:
| Widget | Type | Data source | What it shows |
| -------------------- | ----- | -------------------- | --------------------------------------------------- |
| Postgres Table Sizes | Table | `exec` → `psql` | Top 10 tables with sizes, row counts, vacuum health |
| Redis Memory | Stat | `exec` → `redis-cli` | Memory usage, peak, fragmentation ratio |
| Recent App Errors | Logs | Kubernetes log API | Last error lines from each app pod |
| Cluster Health | Table | Akua API | Cluster status with install health counts |
Open it every morning. If all four widgets look green, grab your coffee. If something's off (a table needs vacuuming, Redis fragmentation is high, error logs are spiking, or an install failed), you see it immediately.
## Why this matters
This dashboard combines **four different data sources** (a SQL database, an in-memory cache, container logs, and the Akua platform API) into a single view. Normally, this means:
* Grafana with Prometheus exporters for Redis and Postgres metrics
* A log aggregation pipeline (Loki, ELK) for application errors
* A separate infrastructure dashboard for cluster health
* Hours of configuration, and ongoing maintenance for all of it
Here, the agent wrote four JavaScript functions in a single conversation. The snippets are disposable. If you want to add a column, change the SQL query, or filter logs differently, tell the agent. No YAML, no exporters, no pipeline configuration.
And because snippets can call any Akua API endpoint, including [exec](/ai/kubernetes-access#command-execution) into any container, the same pattern works for **any application**: MongoDB stats, RabbitMQ queue depths, Nginx traffic analysis, Elasticsearch cluster health, or whatever runs in your pods.
## Related topics
The full workflow for building live dashboards with an agent.
More Postgres, Redis, and chained exec patterns.
The exec and kube proxy endpoints behind these widgets.
More examples of agents composing complex operations.
# Database Operations
Source: https://docs.akua.dev/ai/examples/database-operations
Run SQL queries, check Redis memory, and inspect databases, all through exec
The [exec endpoint](/ai/kubernetes-access#command-execution) isn't just for running `echo hello`. Agents use it to interact with databases, caches, and any CLI tool running inside a container, turning natural language into actual application-level operations.
## PostgreSQL: Table size report
An agent asked "what's the largest table in my Postgres?" runs `psql` inside the container:
```js theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const res = await cnap.request({
method: "POST",
path: `/v1/clusters/${clusterId}:exec`,
body: {
namespace: "default",
pod: "postgres-0",
container: "postgresql",
command: ["psql", "-U", "postgres", "-c", `
SELECT schemaname, tablename,
pg_size_pretty(pg_total_relation_size(schemaname || '.' || tablename)) AS total_size,
pg_size_pretty(pg_relation_size(schemaname || '.' || tablename)) AS data_size,
pg_size_pretty(pg_indexes_size(schemaname || '.' || quote_ident(tablename))) AS index_size,
n_live_tup AS row_count
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(schemaname || '.' || tablename) DESC
LIMIT 15;
`]
}
});
return res.body;
}
```
The agent gets back formatted SQL output with table sizes, index sizes, and row counts. It can then reason about which tables need vacuuming, which indexes are bloated, or whether a migration is needed.
## Redis: Memory analysis
```js theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const info = await cnap.request({
method: "POST",
path: `/v1/clusters/${clusterId}:exec`,
body: {
namespace: "default",
pod: "redis-0",
container: "redis",
command: ["redis-cli", "INFO", "memory"]
}
});
const stats = await cnap.request({
method: "POST",
path: `/v1/clusters/${clusterId}:exec`,
body: {
namespace: "default",
pod: "redis-0",
container: "redis",
command: ["redis-cli", "INFO", "keyspace"]
}
});
return { memory: info.body.output, keyspace: stats.body.output };
}
```
## Chaining queries
The agent can chain multiple queries in a single execution, checking replication lag and then inspecting the slowest queries:
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const exec = (command) => cnap.request({
method: "POST",
path: `/v1/clusters/${clusterId}:exec`,
body: {
namespace: "default",
pod: "postgres-0",
container: "postgresql",
command: ["psql", "-U", "postgres", "-t", "-A", "-c", command]
}
}).then(r => r.body.output.trim());
const [replLag, slowQueries, connCount, dbSize] = await Promise.all([
exec("SELECT CASE WHEN pg_is_in_recovery() THEN extract(epoch FROM now() - pg_last_xact_replay_timestamp())::int || 's' ELSE 'primary' END"),
exec("SELECT query, calls, mean_exec_time::int || 'ms' FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 5"),
exec("SELECT count(*) FROM pg_stat_activity WHERE state = 'active'"),
exec("SELECT pg_size_pretty(pg_database_size(current_database()))"),
]);
return { replication_lag: replLag, slow_queries: slowQueries, active_connections: connCount, database_size: dbSize };
}
```
Four `psql` queries in parallel: replication lag, slowest queries, active connections, database size. All from one `execute` call.
## Why this matters
Database operations through traditional MCP tools would need a dedicated tool per database type (`postgres-query`, `redis-info`, `mongo-stats`), each with their own schema, parameters, and maintenance burden.
With exec + Code Mode, the agent writes the exact command it needs. It knows `psql` flags, `redis-cli` subcommands, and `mongosh` syntax from its training data. No pre-built tools required. The agent composes the right command for any database, any query.
Exec is non-interactive with a 30-second timeout. It's ideal for read queries and diagnostics. For long-running operations or interactive sessions, use the dashboard terminal.
## Related topics
Combine database exec queries with cluster health in one dashboard.
The exec endpoint request and response shape.
Adaptive SRE triage using pod health, events, and logs.
How agents chain multiple operations in one call.
# Incident Debugging
Source: https://docs.akua.dev/ai/examples/incident-debugging
Full SRE triage in one conversation: pod status, events, error logs, and rollout history
An agent asked "why is my app returning 500s?" runs a full incident triage: checking pod health, recent Kubernetes events, error logs, and deployment rollout history, all composed across multiple `execute` calls, reasoning about each result before deciding what to check next.
## The triage flow
This isn't a single code block. It's how the agent *thinks*. Each step is one `execute` call, but the agent decides what to check based on what it finds.
### Step 1: Pod health check
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const namespace = "production"; // resolved by the agent from conversation
const kube = (path) => cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
}).then(r => r.body);
const pods = await kube(`api/v1/namespaces/${namespace}/pods`);
return pods.items.map(p => ({
name: p.metadata.name,
phase: p.status.phase,
restarts: p.status.containerStatuses?.reduce((s, c) => s + c.restartCount, 0) || 0,
ready: p.status.containerStatuses?.every(c => c.ready) || false,
containers: p.status.containerStatuses?.map(c => ({
name: c.name,
ready: c.ready,
restarts: c.restartCount,
state: Object.keys(c.state || {})[0],
reason: c.state?.waiting?.reason || c.state?.terminated?.reason || null,
})),
}));
}
```
The agent sees a pod in `CrashLoopBackOff` with 12 restarts. It decides to check events and logs.
### Step 2: Recent events
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const namespace = "production"; // from step 1
const podName = "api-proxy-7f8b4c..."; // from step 1 results
const kube = (path) => cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
}).then(r => r.body);
const events = await kube(
`api/v1/namespaces/${namespace}/events?fieldSelector=involvedObject.name=${podName}`
);
// Sort by last timestamp, return most recent
return events.items
.sort((a, b) => new Date(b.lastTimestamp) - new Date(a.lastTimestamp))
.slice(0, 15)
.map(e => ({
type: e.type,
reason: e.reason,
message: e.message,
count: e.count,
last: e.lastTimestamp,
}));
}
```
Events show `OOMKilled`. The container ran out of memory. The agent checks logs to confirm.
### Step 3: Error logs
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const namespace = "production"; // from step 1
const podName = "api-proxy-7f8b4c..."; // from step 1 results
const logs = await cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/api/v1/namespaces/${namespace}/pods/${podName}/log`,
query: { tailLines: "200", previous: "true" },
}).then(r => r.body);
// Filter for errors and warnings
const lines = logs.split("\n");
const errors = lines.filter(l =>
/error|fatal|panic|exception|oom|killed/i.test(l)
);
return {
total_lines: lines.length,
error_lines: errors.length,
errors: errors.slice(-20),
};
}
```
Note `previous: "true"`: the agent fetches logs from the *crashed* container, not the restarting one. It finds memory allocation failures in the last 20 error lines.
### Step 4: Deployment rollout history
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const namespace = "production"; // from step 1
const deploymentName = "api-proxy"; // from step 1 results
const kube = (path) => cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
}).then(r => r.body);
const [deployment, replicaSets] = await Promise.all([
kube(`apis/apps/v1/namespaces/${namespace}/deployments/${deploymentName}`),
kube(`apis/apps/v1/namespaces/${namespace}/replicasets`),
]);
// Find ReplicaSets owned by this deployment
const owned = replicaSets.items
.filter(rs => rs.metadata.ownerReferences?.some(o => o.name === deploymentName))
.sort((a, b) => parseInt(b.metadata.annotations?.["deployment.kubernetes.io/revision"] || "0")
- parseInt(a.metadata.annotations?.["deployment.kubernetes.io/revision"] || "0"));
return {
current_image: deployment.spec.template.spec.containers[0]?.image,
current_limits: deployment.spec.template.spec.containers[0]?.resources?.limits,
revisions: owned.slice(0, 5).map(rs => ({
revision: rs.metadata.annotations?.["deployment.kubernetes.io/revision"],
image: rs.spec.template.spec.containers[0]?.image,
replicas: rs.status.replicas,
created: rs.metadata.creationTimestamp,
})),
};
}
```
The agent finds that the latest revision changed the image but *removed* memory limits. Root cause identified.
## Why this matters
An SRE manually doing this would:
1. `kubectl get pods` to check status
2. `kubectl describe pod` to read events
3. `kubectl logs --previous` to check crash logs
4. `kubectl rollout history` to check what changed
That's 4 separate commands with raw output they need to mentally parse. The agent does it in 4 `execute` calls, but each one filters and extracts only what's relevant. The LLM reasons about structured findings, not walls of YAML.
More importantly, the agent *adapts*. It doesn't run a fixed checklist. It sees `OOMKilled` and decides to check previous container logs and deployment history. A traditional MCP tool would need a pre-built "debug pod" tool that tries to anticipate every scenario.
## Related topics
The kube proxy and exec endpoints used in each triage step.
Proactive security checks before incidents occur.
Fetch and count logs across all pods in a single call.
Ambient agents that start triage automatically on deploy failures.
# Parallel Log Analysis
Source: https://docs.akua.dev/ai/examples/parallel-log-analysis
35,000 log lines across 11 containers in 506ms, one tool call
An agent asked to "count log lines across all pods in my cluster" produced this in a single `execute` call. No sequential tool calls, no raw logs in the context window.
## The Numbers
| Metric | Value |
| ------------------------------------ | --------- |
| Total time | **506ms** |
| List all pods | 139ms |
| Parallel log fetches (11 containers) | 367ms |
| Total log lines counted | 35,498 |
| API calls made inside sandbox | 12 |
| Tool calls seen by the LLM | **1** |
The agent even self-instrumented the timing with `Date.now()` inside the sandbox.
## The Code
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const kube = (path) => cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`
}).then(r => r.body);
// Get all pods across all namespaces
const allPods = await kube("api/v1/pods");
// Fetch logs for all running containers in parallel
const results = await Promise.all(
allPods.items
.filter(p => p.status.phase === "Running")
.flatMap(p =>
p.spec.containers.map(c => ({
namespace: p.metadata.namespace,
pod: p.metadata.name,
container: c.name
}))
)
.map(async ({ namespace, pod, container }) => {
try {
const logs = await kube(
`api/v1/namespaces/${namespace}/pods/${pod}/log?container=${container}`
);
const lines = typeof logs === "string"
? logs.split("\n").filter(Boolean).length : 0;
return { namespace, pod, container, lines };
} catch {
return { namespace, pod, container, lines: 0, error: true };
}
})
);
const total = results.reduce((sum, r) => sum + r.lines, 0);
results.sort((a, b) => b.lines - a.lines);
return { total_lines: total, per_pod: results };
}
```
## Why this matters
With traditional MCP tools, this would be 12+ sequential round trips: one to list pods, then one per container to fetch logs. Each round trip adds network latency, and every raw response gets dumped into the LLM's context window.
Code Mode does it in **one** tool call. The agent's code filters, aggregates, and formats the data inside the sandbox before returning. Only the summary hits the context window, not 35,000 lines of raw logs.
## What the agent does
1. Lists all pods across all namespaces
2. Filters for running pods, expands to per-container list
3. Fans out `Promise.all()` across 11 log fetches in parallel
4. Counts lines per container, handles errors gracefully
5. Sorts by line count, returns a clean summary
The heaviest pod (api-proxy, 24,828 lines) took 367ms. Small pods (\~10 lines) came back in \~89ms. The parallel fan-out means total time equals the slowest fetch, not the sum.
## Related topics
More examples of the parallel fan-out pattern.
Adaptive SRE triage: logs, events, rollout history.
Cluster-wide CPU and memory report in a single API call.
The kube proxy log endpoint used in this example.
# Resource Audit
Source: https://docs.akua.dev/ai/examples/resource-audit
Cluster-wide CPU/memory capacity report in 56ms from a single API call
An agent asked to "count all resource requests and limits across all pods" returned a full capacity report in **56ms** from a **single API call**. All the computation happened inside the sandbox.
## The Numbers
| Metric | Value |
| ----------------------------- | -------- |
| Total time | **56ms** |
| API calls made inside sandbox | 1 |
| Pods analyzed | 11 |
| Tool calls seen by the LLM | **1** |
## The Code
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const allPods = await cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/api/v1/pods`,
}).then(r => r.body);
// Unit parsers — written by the agent, executed in the sandbox
const parseCpu = (v) => {
if (!v) return 0;
if (v.endsWith("m")) return parseInt(v) / 1000;
return parseFloat(v);
};
const parseMem = (v) => {
if (!v) return 0;
if (v.endsWith("Gi")) return parseFloat(v) * 1024;
if (v.endsWith("Mi")) return parseFloat(v);
if (v.endsWith("Ki")) return parseFloat(v) / 1024;
return parseFloat(v) / (1024 * 1024);
};
const totals = { requests: { cpu: 0, memMi: 0 }, limits: { cpu: 0, memMi: 0 } };
const perPod = [];
for (const pod of allPods.items.filter(p => p.status.phase === "Running")) {
const podRes = { requests: { cpu: 0, memMi: 0 }, limits: { cpu: 0, memMi: 0 } };
for (const c of pod.spec.containers) {
const r = c.resources || {};
podRes.requests.cpu += parseCpu(r.requests?.cpu);
podRes.requests.memMi += parseMem(r.requests?.memory);
podRes.limits.cpu += parseCpu(r.limits?.cpu);
podRes.limits.memMi += parseMem(r.limits?.memory);
}
totals.requests.cpu += podRes.requests.cpu;
totals.requests.memMi += podRes.requests.memMi;
totals.limits.cpu += podRes.limits.cpu;
totals.limits.memMi += podRes.limits.memMi;
perPod.push({
pod: pod.metadata.name,
ns: pod.metadata.namespace,
requests: { cpu: `${Math.round(podRes.requests.cpu * 1000)}m`, mem: `${Math.round(podRes.requests.memMi)}Mi` },
limits: { cpu: `${Math.round(podRes.limits.cpu * 1000)}m`, mem: `${Math.round(podRes.limits.memMi)}Mi` },
});
}
return {
pod_count: perPod.length,
totals: {
requests: { cpu: `${Math.round(totals.requests.cpu * 1000)}m`, mem: `${Math.round(totals.requests.memMi)}Mi` },
limits: { cpu: `${Math.round(totals.limits.cpu * 1000)}m`, mem: `${Math.round(totals.limits.memMi)}Mi` },
},
per_pod: perPod.sort((a, b) => parseInt(b.requests.mem) - parseInt(a.requests.mem)),
};
}
```
## Why this matters
The Kubernetes API returns raw pod specs: CPU in millicores (`"100m"`), memory in mixed units (`"256Mi"`, `"1Gi"`, `"131072Ki"`). A traditional MCP tool would dump all that raw JSON into the LLM's context and hope it can do math.
Code Mode puts the computation in the sandbox. The agent wrote unit parsers for CPU and memory, iterated every container in every running pod, aggregated totals, and returned a clean capacity report. The LLM context received a sorted summary, not the raw specs of 11 pods.
## What the agent does
1. Fetches all pods across all namespaces (single API call)
2. Writes CPU millicore and memory unit parsers
3. Iterates every container in every running pod
4. Aggregates requests and limits per-pod and cluster-wide
5. Converts back to human-readable units, sorts by memory
6. Returns a formatted capacity report
## Related topics
35,000 log lines across 11 pods in 506ms. Same fan-out approach.
Includes per-container resource limit checks.
Extend resource audits across your entire fleet.
How in-sandbox computation avoids flooding the context window.
# Security Audit
Source: https://docs.akua.dev/ai/examples/security-audit
9 security checks across 7 parallel API calls: full cluster security posture in one tool call
An agent asked to "audit the cluster for security" ran 9 different security checks across 7 parallel Kubernetes API calls (pods, services, secrets, RBAC roles, RBAC bindings, network policies, and nodes), all in a single `execute` call.
## What it checks
| Check | What it looks for |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Pod security context | Privileged containers, running as root, privilege escalation, writable root filesystem, capabilities not dropped |
| Image tags | Containers using `:latest` instead of pinned tags |
| Resource limits | Missing requests or limits |
| Exposed services | NodePort or LoadBalancer services directly accessible |
| RBAC: cluster-admin | Non-system bindings to the `cluster-admin` role |
| RBAC: wildcards | Roles with `*` on resources, verbs, or API groups |
| Network policies | Namespaces with no network policies (unrestricted pod-to-pod traffic) |
| Host namespaces | Pods using `hostNetwork`, `hostPID`, or `hostIPC` |
| Service account tokens | Non-system pods with automounted service account tokens |
## The Code
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const kube = (path) => cnap.request({
method: "GET",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
}).then(r => r.body);
// 7 API calls in parallel
const [pods, services, secrets, clusterRoles, clusterRoleBindings, networkPolicies, nodes] =
await Promise.all([
kube("api/v1/pods"),
kube("api/v1/services"),
kube("api/v1/secrets"),
kube("apis/rbac.authorization.k8s.io/v1/clusterroles"),
kube("apis/rbac.authorization.k8s.io/v1/clusterrolebindings"),
kube("apis/networking.k8s.io/v1/networkpolicies"),
kube("api/v1/nodes"),
]);
// 1. Pod security audit
const podIssues = [];
for (const pod of pods.items) {
for (const c of pod.spec.containers) {
const sc = c.securityContext || {};
const issues = [];
if (sc.privileged) issues.push("privileged");
if (sc.runAsUser === 0 || (!sc.runAsNonRoot && !pod.spec.securityContext?.runAsNonRoot))
issues.push("may run as root");
if (sc.allowPrivilegeEscalation !== false) issues.push("privilege escalation allowed");
if (!sc.readOnlyRootFilesystem) issues.push("writable root filesystem");
if (!sc.capabilities?.drop?.includes("ALL")) issues.push("capabilities not dropped");
if (c.image?.includes(":latest")) issues.push("uses :latest tag");
if (!c.resources?.limits) issues.push("no resource limits");
if (!c.resources?.requests) issues.push("no resource requests");
if (issues.length > 0) {
podIssues.push({ pod: pod.metadata.name, ns: pod.metadata.namespace, container: c.name, issues });
}
}
}
// 2. Secrets in default namespace
const defaultSecrets = secrets.items
.filter(s => s.metadata.namespace === "default" && s.type !== "kubernetes.io/service-account-token")
.map(s => ({ name: s.metadata.name, type: s.type }));
// 3. Services exposed externally
const exposedServices = services.items
.filter(s => s.spec.type === "NodePort" || s.spec.type === "LoadBalancer")
.map(s => ({ name: s.metadata.name, ns: s.metadata.namespace, type: s.spec.type }));
// 4. Overly permissive RBAC
const dangerousBindings = clusterRoleBindings.items
.filter(b => b.roleRef.name === "cluster-admin")
.map(b => ({
name: b.metadata.name,
subjects: b.subjects?.map(s => `${s.kind}:${s.namespace || ""}/${s.name}`),
}));
// 5. Wildcard RBAC rules
const wildcardRoles = clusterRoles.items
.filter(r => r.rules?.some(rule =>
rule.resources?.includes("*") || rule.verbs?.includes("*") || rule.apiGroups?.includes("*")
))
.map(r => r.metadata.name);
// 6. Network policies per namespace
const allNs = [...new Set(pods.items.map(p => p.metadata.namespace))];
const npByNs = {};
for (const np of networkPolicies.items) {
npByNs[np.metadata.namespace] = (npByNs[np.metadata.namespace] || 0) + 1;
}
const nsWithoutNetpol = allNs.filter(ns => !npByNs[ns]);
// 7. Host namespaces
const hostNsPods = pods.items
.filter(p => p.spec.hostNetwork || p.spec.hostPID || p.spec.hostIPC)
.map(p => ({ pod: p.metadata.name, ns: p.metadata.namespace }));
// 8. SA token automount
const automountPods = pods.items
.filter(p => p.spec.automountServiceAccountToken !== false && !p.metadata.namespace.startsWith("kube-"))
.map(p => ({ pod: p.metadata.name, ns: p.metadata.namespace, sa: p.spec.serviceAccountName }));
// 9. Node info
const nodeInfo = nodes.items.map(n => ({
name: n.metadata.name,
kubelet: n.status.nodeInfo.kubeletVersion,
os: n.status.nodeInfo.osImage,
containerRuntime: n.status.nodeInfo.containerRuntimeVersion,
}));
return {
summary: {
total_pods: pods.items.length,
total_containers: pods.items.reduce((s, p) => s + p.spec.containers.length, 0),
containers_with_issues: podIssues.length,
},
pod_security: podIssues,
host_namespace_pods: hostNsPods,
exposed_services: exposedServices,
cluster_admin_bindings: dangerousBindings,
wildcard_rbac_roles: wildcardRoles,
namespaces_without_network_policies: nsWithoutNetpol,
sa_automount_tokens: automountPods,
non_default_secrets: defaultSecrets,
node_info: nodeInfo,
};
}
```
## Why this matters
A traditional approach would require the agent to make 7+ sequential tool calls just to fetch the data, then somehow reason about all the raw JSON in its context window. The context would be flooded with every pod spec, every RBAC rule, every service definition.
Code Mode runs all 7 fetches in parallel and does the analysis inside the sandbox. The agent wrote the security checks (privileged containers, missing capabilities, writable filesystems, RBAC wildcards, network policy gaps) as JavaScript logic. The LLM receives a structured findings report, not raw Kubernetes API responses.
## What the agent does
1. Fires 7 Kubernetes API calls in parallel (`Promise.all`)
2. Audits every container's security context (8 checks per container)
3. Identifies overly permissive RBAC bindings and wildcard roles
4. Finds namespaces with no network policies
5. Flags pods using host namespaces or automounted service account tokens
6. Collects node runtime info for version auditing
7. Returns a structured report with findings grouped by severity
## From audit to remediation
The agent doesn't just report findings; it can fix them. After the audit flagged zero network policies across all namespaces, a follow-up "create network policies for my installs" produced two more `execute` calls:
**Step 1 (Discovery):** fetched services and pods from each install namespace in parallel to learn which ports each app needs.
**Step 2 (Apply policies):** created 3 network policies per namespace using `POST` through the kube proxy:
```js expandable theme={null}
async () => {
const clusterId = "cls_abc123"; // resolved by the agent from conversation
const kubePost = (path, body) => cnap.request({
method: "POST",
path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
body,
}).then(r => ({ status: r.status, name: r.body?.metadata?.name }));
const namespaces = [
{ ns: "inst-k17236...", name: "cloudflare-gateway", ports: [] },
{ ns: "inst-k1737k...", name: "openclaw2", ports: [18789] },
{ ns: "inst-k174wk...", name: "httpbin", ports: [8000] },
{ ns: "inst-k175jm...", name: "openclaw", ports: [18789] },
];
const results = [];
for (const { ns, name, ports } of namespaces) {
const apiPath = `apis/networking.k8s.io/v1/namespaces/${ns}/networkpolicies`;
// 1. Default deny all ingress + egress
const defaultDeny = await kubePost(apiPath, {
apiVersion: "networking.k8s.io/v1",
kind: "NetworkPolicy",
metadata: { name: "default-deny-all", namespace: ns },
spec: { podSelector: {}, policyTypes: ["Ingress", "Egress"] },
});
// 2. Allow DNS egress to kube-system
const allowDns = await kubePost(apiPath, {
apiVersion: "networking.k8s.io/v1",
kind: "NetworkPolicy",
metadata: { name: "allow-dns", namespace: ns },
spec: {
podSelector: {},
policyTypes: ["Egress"],
egress: [{
to: [{ namespaceSelector: { matchLabels: { "kubernetes.io/metadata.name": "kube-system" } } }],
ports: [{ protocol: "UDP", port: 53 }, { protocol: "TCP", port: 53 }],
}],
},
});
// 3. Allow ingress on app ports (if any)
let allowIngress = null;
if (ports.length > 0) {
allowIngress = await kubePost(apiPath, {
apiVersion: "networking.k8s.io/v1",
kind: "NetworkPolicy",
metadata: { name: "allow-app-ingress", namespace: ns },
spec: {
podSelector: {},
policyTypes: ["Ingress"],
ingress: [{ ports: ports.map(p => ({ protocol: "TCP", port: p })) }],
},
});
}
results.push({ install: name, defaultDeny, allowDns, allowIngress });
}
return results;
}
```
The result: 3 policies per namespace, all returning `201 Created`:
| Install | default-deny-all | allow-dns | allow-app-ingress |
| ------------------ | :--------------: | :-------: | :---------------: |
| cloudflare-gateway | ✓ | ✓ | — (no ports) |
| openclaw2 | ✓ | ✓ | ✓ (TCP 18789) |
| httpbin | ✓ | ✓ | ✓ (TCP 8000) |
| openclaw | ✓ | ✓ | ✓ (TCP 18789) |
Each namespace is now isolated. Pods can only receive traffic on their app port and make DNS queries. No cross-namespace traffic. The agent went from finding the problem to fixing it without leaving the conversation.
## Related topics
Run the same security checks across your entire fleet.
Adaptive triage for when security issues cause failures.
The kube proxy endpoints behind these API calls.
How the parallel fan-out and in-sandbox analysis pattern works.
# AI & Agents
Source: https://docs.akua.dev/ai/index
Connect AI assistants to Akua through MCP servers, or use the embedded dashboard agent for guided deployment and operations
Akua is built for agentic operations. You can use the embedded dashboard agent for guided deployment and operations work, or connect your own AI tool through the [Model Context Protocol (MCP)](https://modelcontextprotocol.io). Both paths use the same platform API, workspace controls, and operational context.
## What you can do
Use the embedded dashboard agent or configure workspace agents that investigate, propose, and automate operations inside Akua.
Search and query Akua docs in real-time. No authentication required. Works out of the box with any MCP client.
Manage clusters, products, and installs via the Akua API from external AI tools. Uses OAuth 2.1 and sandboxed Code Mode.
How agents read, prepare, and review changes to Akua installations through their git repositories.
Give agents direct access to cluster resources through the Kubernetes API proxy and command execution.
Use AI agents to generate and iterate on custom dashboards and snippets conversationally.
See real examples of agents composing complex multi-step operations in a single tool call.
Concrete examples: log analysis, security audits, cross-cluster comparison, incident debugging, and more.
## Quick setup
Connect your AI tool in under a minute when you want Claude Code, Cursor, or another MCP-compatible client to work with Akua.
```bash theme={null}
claude mcp add --transport http akua-docs https://docs.akua.dev/mcp
claude mcp add --transport http akua https://mcp.akua.dev
```
Verify:
```bash theme={null}
claude mcp list
```
Press `Cmd+Shift+P` → "Open MCP settings" → Add:
```json mcp.json theme={null}
{
"mcpServers": {
"akua-docs": {
"url": "https://docs.akua.dev/mcp"
},
"akua": {
"url": "https://mcp.akua.dev"
}
}
}
```
Create `.vscode/mcp.json`:
```json .vscode/mcp.json theme={null}
{
"servers": {
"akua-docs": {
"type": "http",
"url": "https://docs.akua.dev/mcp"
},
"akua": {
"type": "http",
"url": "https://mcp.akua.dev"
}
}
}
```
Config file location:
* macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
* Windows: `%APPDATA%\Claude\claude_desktop_config.json`
* Linux: `~/.config/claude/claude_desktop_config.json`
```json claude_desktop_config.json theme={null}
{
"mcpServers": {
"akua-docs": {
"command": "npx",
"args": ["mcp-remote", "https://docs.akua.dev/mcp"]
},
"akua": {
"command": "npx",
"args": ["mcp-remote", "https://mcp.akua.dev"]
}
}
}
```
On first connection to the platform server, your browser will open for OAuth authorization.
Add the MCP server URLs to your tool's configuration:
```json theme={null}
{
"mcpServers": {
"akua-docs": {
"url": "https://docs.akua.dev/mcp"
},
"akua": {
"url": "https://mcp.akua.dev"
}
}
}
```
Configuration format may vary. Refer to your tool's documentation.
| Server | URL | Auth | Use case |
| ----------- | --------------------------- | --------- | ----------------------------------- |
| `akua-docs` | `https://docs.akua.dev/mcp` | None | Search and query docs |
| `akua` | `https://mcp.akua.dev` | OAuth 2.1 | Manage clusters, products, installs |
You can set up just one server if you only need docs search or only need API access.
## Beyond MCP
Akua's AI integration goes beyond MCP servers:
* **Contextual menu**: every doc page offers copy-as-markdown, open-in-AI, and one-click editor setup
* **llms.txt**: industry-standard files (`llms.txt` and `llms-full.txt`) for AI indexing
* **Markdown access**: append `.md` to any doc URL for AI-friendly output (for example, `docs.akua.dev/ai/index.md`)
## Related topics
The embedded dashboard agent and the full agent product model.
How Code Mode gives agents full API access in a sandboxed V8 isolate.
See agents in action: log analysis, security audits, and more.
Build on the public agent resources and SDK shape.
# Kubernetes access
Source: https://docs.akua.dev/ai/kubernetes-access
Give AI agents direct access to cluster resources through the Kubernetes API proxy and command execution
The platform MCP server includes a transparent Kubernetes API proxy and a command execution endpoint. Together, they let agents read pod logs, list resources, inspect deployments, discover CRDs, and run commands, all through the same `cnap.request()` interface.
These endpoints are accessed through the [Platform MCP](/ai/platform-mcp) server's `execute` tool. The agent writes JavaScript that calls `cnap.request()`.
## Kube API proxy
`GET /v1/clusters/{id}/kube_proxy/{path}` proxies any request to the cluster's Kubernetes API server. The path after `/kube_proxy/` is forwarded directly, along with query parameters.
### Pod logs
Fetch pod logs as plain text:
```js theme={null}
async () => {
const res = await cnap.request({
method: "GET",
path: "/v1/clusters/CLUSTER_ID/kube_proxy/api/v1/namespaces/NAMESPACE/pods/POD_NAME/log",
query: { tailLines: "100" }
});
return res.body;
}
```
### List resources
List pods, deployments, configmaps, services, or any Kubernetes resource:
```js theme={null}
async () => {
// List pods in a namespace
const res = await cnap.request({
method: "GET",
path: "/v1/clusters/CLUSTER_ID/kube_proxy/api/v1/namespaces/default/pods"
});
return res.body.items.map(p => ({
name: p.metadata.name,
status: p.status.phase
}));
}
```
```js theme={null}
async () => {
// List deployments
const res = await cnap.request({
method: "GET",
path: "/v1/clusters/CLUSTER_ID/kube_proxy/apis/apps/v1/namespaces/default/deployments"
});
return res.body.items.map(d => ({
name: d.metadata.name,
replicas: d.status.readyReplicas + "/" + d.spec.replicas
}));
}
```
### API discovery
Agents can discover cluster-specific APIs (including CRDs) by fetching the Kubernetes OpenAPI spec:
```
GET /v1/clusters/{id}/kube_proxy/openapi/v3
```
This is useful when the agent needs to work with custom resources it hasn't seen before. It can inspect the spec, find the right API group and version, then make calls.
### Supported methods
The proxy supports all HTTP methods (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`), so agents can also create and modify resources when needed.
## Command execution
`POST /v1/clusters/{id}:exec` runs a command in a pod container and returns the combined output:
```js theme={null}
async () => {
const res = await cnap.request({
method: "POST",
path: "/v1/clusters/CLUSTER_ID:exec",
body: {
namespace: "default",
pod: "postgres-0",
container: "postgresql",
command: ["psql", "-c", "SELECT version();"]
}
});
return res.body;
// { output: "PostgreSQL 16.1 ...\n", exit_code: 0, duration_ms: 142 }
}
```
### Request body
| Field | Type | Required | Description |
| ----------- | ---------- | -------- | ----------------------------- |
| `namespace` | `string` | Yes | Kubernetes namespace |
| `pod` | `string` | Yes | Pod name |
| `container` | `string` | No | Container name within the pod |
| `command` | `string[]` | Yes | Command and arguments |
### Response
| Field | Type | Description |
| ------------- | --------- | ------------------------------------------- |
| `output` | `string` | Combined command output (stdout and stderr) |
| `exit_code` | `integer` | Exit code (`0` = success) |
| `duration_ms` | `number` | Execution time in milliseconds |
Exec is non-interactive (no TTY, no stdin) with a 30-second timeout. For interactive shells, use the dashboard terminal.
## Security
* **Authentication** is handled server-side. Agents cannot read or set the `Authorization` header.
* **Authorization** checks workspace membership before proxying any request.
* All code runs in a **sandboxed V8 isolate** with no access to the filesystem, network, or Node.js APIs.
* The kube proxy has a **30-second timeout** per request.
* Exec commands have a **30-second timeout** and are non-interactive.
## Related topics
See how agents compose complex operations in a single call.
The MCP server that provides these endpoints.
Discover and interact with custom Kubernetes resources.
Full SRE triage using pod health, events, logs, and rollout history.
# Platform MCP
Source: https://docs.akua.dev/ai/platform-mcp
Connect AI agents to the Akua API via the Model Context Protocol
The platform MCP server gives AI agents full programmatic access to Akua: managing clusters, deploying products, monitoring infrastructure, and automating operations through the same API that powers the dashboard.
```
https://mcp.akua.dev
```
Authentication uses **OAuth 2.1** with PKCE. MCP clients that support the [MCP authorization spec](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization) handle this automatically.
This is the **platform** MCP server for managing Akua resources from external AI tools. If you want the managed dashboard experience instead, use [Hosted Agents](/agents).
## Why Code Mode
Most MCP servers register one tool per API endpoint (`list-clusters`, `get-install`, `create-product`, and so on). As the API grows, the tool list explodes, eating context window tokens and requiring constant maintenance.
**Code Mode** (also called **programmatic tool calling**) replaces hundreds of individual tools with just two:
1. **`search`**: discover endpoints by querying the OpenAPI spec
2. **`execute`**: call endpoints by writing JavaScript against a typed API client
The agent writes code to make API calls, chain results, and filter data, all in a single tool invocation. A single `execute` call can fan out dozens of internal API requests in parallel, aggregate results, and return a summary. Less token overhead, fewer round trips, and zero maintenance when the API evolves.
Inspired by [CodeAct](https://machinelearning.apple.com/research/codeact), this works because LLMs are better at writing code than making individual tool calls. They have seen millions of lines of real-world code but only contrived tool-calling examples.
Hosted Agents use the same idea when a dashboard conversation only needs structured platform work. A user can ask "deploy this repository" in the sidebar, and the agent can search the API, call the right endpoints, render approval prompts, and show progress without starting a retained runtime. If the task needs files, git, package managers, or tests, the agent can move into a retained runtime while keeping the same conversation.
Apple ML research on LLM code generation for tool use
Cloudflare's introduction of the pattern
Anthropic's recommended approach
Akua's implementation uses the open-source [`akua-dev/codemode`](https://github.com/akua-dev/codemode) library.
## How it works
```mermaid theme={null}
sequenceDiagram
participant Agent as AI Agent
participant MCP as Akua MCP Server
participant Sandbox as V8 Sandbox
participant API as Akua API
Agent->>MCP: search({ code: "..." })
MCP->>Sandbox: Execute against OpenAPI spec
Sandbox-->>Agent: Matching endpoints
Agent->>MCP: execute({ code: "..." })
MCP->>Sandbox: Run agent's JavaScript
Sandbox->>API: cnap.request() (auth injected)
API-->>Sandbox: Response
Sandbox-->>Agent: Results
```
## Tools
### `search`
Discover available API endpoints by querying the OpenAPI spec. The agent writes a JavaScript function that receives the full spec as `spec`:
```js theme={null}
// List all endpoints
async () => {
const results = [];
for (const [path, methods] of Object.entries(spec.paths)) {
for (const [method, op] of Object.entries(methods)) {
results.push({ method: method.toUpperCase(), path, summary: op.summary });
}
}
return results;
}
```
### `execute`
Call API endpoints by writing JavaScript that uses `cnap.request()`. The agent discovers endpoints with `search` first, then calls them:
```js theme={null}
// List all workspaces
async () => {
const res = await cnap.request({ method: "GET", path: "/v1/workspaces" });
return res.body;
}
```
```js theme={null}
// Chain calls: find a workspace, then list its clusters
async () => {
const ws = await cnap.request({ method: "GET", path: "/v1/workspaces" });
const first = ws.body.data[0];
const clusters = await cnap.request({
method: "GET",
path: "/v1/clusters",
headers: { "Akua-Context": first.id }
});
return { workspace: first.name, clusters: clusters.body.data };
}
```
Authentication is handled automatically. The agent cannot set or read the `Authorization` header. All requests run inside a sandboxed V8 isolate.
## Kubernetes access
The API includes a transparent Kubernetes proxy and a command execution endpoint, giving agents direct access to cluster resources: pod logs, resource listing, API discovery, and running commands.
Learn how agents use the kube proxy and exec endpoints with full examples
## Resources and prompts
The MCP server also exposes resources and prompts:
| Type | Name | Description |
| -------- | ------------------------- | ------------------------------------------------------- |
| Resource | `cnap://user/profile` | Current authenticated user info |
| Prompt | `infrastructure-overview` | Analyze clusters, installs, and products in a workspace |
| Prompt | `deployment-status` | Check deployment health and identify issues |
Both prompts accept a `workspaceId` argument.
## Security
All agent-generated code runs in a **sandboxed V8 isolate** with strict resource limits. There is no access to Node.js APIs, the filesystem, or the network beyond the Akua API.
* **No auth access**: the sandbox cannot read or set the `Authorization` header; auth is injected server-side
* **Memory limit**: 64 MB per isolate
* **CPU timeout**: 30 seconds
* **Request limit**: 50 API calls per execution
* **Response limit**: 10 MB max response size
* **In-process routing**: requests never leave the server
## Related topics
See real examples of agents composing complex operations.
Kube API proxy, pod logs, and command execution.
Search and query Akua docs in real-time.
The embedded dashboard agent and full agent product model.
# Agents and installation repositories
Source: https://docs.akua.dev/ai/repo-agents
How AI agents read, prepare, and review changes to Akua installations through their git repositories
Every installation on Akua lives in its own git repository. That repository is the surface AI agents work against: clone it for context, fork it to prepare a change, and review the result before it reaches the deployed branch. The same primitives a human operator uses through `git` are what an agent uses through code.
Repository change requests are the review boundary for agent-authored source or configuration changes. Agents can inspect existing work, create a fork-backed change request, push scoped commits, and ask a human or policy gate to accept it.
## Why a repository is the right surface for agents
An installation's repository is a small, well-typed world:
* **`inputs.yaml`**: what the customer chose. Read-only context for an agent debugging a deploy.
* **`package.k`**: the composition logic. The exact lever for "add a sidecar", "patch a field", "swap an image registry".
* **`manifests/`**: the rendered output. Diffable against any previous deploy.
* **`upstream/`**: the pinned source. Stable across renders.
Agents don't need a custom API for "edit this deployment". They need git. Every modern coding agent already knows how to clone, edit, branch, and submit a diff. Akua makes the deployment look like a normal repository so those skills transfer directly.
## Repository access
### Read installation context
Mint a [read-only token](/apis/authentication) for your workspace and clone any installation's repository. The token can fetch but cannot push, so an agent reading context can't accidentally modify the deployment.
```bash theme={null}
# Mint a read-only token via the dashboard, then:
git clone https://:@git.akua.dev//.git
cd
# Agent reads the relevant files
cat inputs.yaml
cat package.k
ls manifests/
```
This is the foundation for any agent that diagnoses a deployment, summarizes a configuration, or compares two installations. The tokens enforce the boundary: a leaked read-token cannot push, regardless of how it ends up misused.
### Prepare reviewable changes
When an agent needs to change a deployment, it should create a repository change request instead of pushing to the deployed branch. The change request creates or references a fork repository, exposes a scoped token for that fork, and keeps the review lifecycle in the API.
### The shape
A repository change request is a typed object on Akua that wraps a git fork:
* **`parent_repository_id`**: points at the parent installation's repository
* **`fork_repository_id`**: points at the fork that contains the proposed commits
* **`expires_at`**: a deadline; abandoned change requests are reaped by policy
* **`change_type`**: what flavour of change: `manifest_patch`, `inputs_change`, or `package_change`
* **A reviewer-facing diff**: rendered in the dashboard for human review
An agent or human creates a repository change request, pushes commits to its fork, and the dashboard renders the diff. A human with accept rights accepts; Akua validates the fork, updates the parent repository, renders the installation, and deploys the result. Rejections close the change request; expired change requests are garbage-collected.
### Why three change types
Different changes carry different blast radius, so they get different review surfaces:
| Change type | What changes | Review surface |
| ---------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `manifest_patch` | A targeted patch to one or more rendered resources, expressed as a structured patch (not free-form YAML). | Side-by-side patch + affected-resources list. |
| `inputs_change` | A diff in `inputs.yaml`. The reviewer sees both the input diff and the resulting manifest diff. | "Before" + "after" rendered manifests with field-level highlights. |
| `package_change` | A diff in `package.k` (composition logic). | Full source diff + render of both versions. |
The three change types let Akua gate review tooling appropriately: an inputs change is usually safer than a composition change, and the UI can lead with that distinction.
### Manifest-path protection
Repository change requests never touch `manifests/` directly. They edit the source (`inputs.yaml`, `package.k`) and Akua re-renders. This keeps the rendered tree authoritative and prevents an agent from sneaking changes that the source files don't reflect: every byte your cluster applies is reproducible from the repository's source.
### Per-repo token scoping
Repository change request tokens are scoped to the fork repository and a requested access level. A token an agent uses to push to a fork should only push to that fork, not to the deployed branch and not to any other installation repository.
## Designing agents against this model
If you're building an agent that integrates with Akua, design for repository change requests:
1. **Default to read-only.** Mint a read scope token unless you have a clear reason for write. It's the smallest surface and the easiest to revoke.
2. **Compute diffs, don't write to the deployed branch.** Push to the repository change request fork and let a human or policy gate review it.
3. **Stay in the source files.** Edits to `inputs.yaml` and `package.k` survive re-renders and updates. Edits to `manifests/` get clobbered on the next render.
4. **Hash before you push.** Akua skips no-op deploys based on the manifest hash, so equivalent edits produce no churn (but only if your changes don't pull in irrelevant whitespace or ordering noise).
5. **Time-box your work.** Repository change requests carry `expires_at`, and abandoned drafts are reaped. Build agent loops that close their own change requests on completion or failure.
## Related topics
The git-backed model behind every installation.
Edit inputs, patch resources, and review repository changes.
Endpoints, parameters, try-it playground.
Mint API tokens for agent access.
# Akua
Source: https://docs.akua.dev/akua/index
The packaging substrate behind every Akua installation
[Akua](https://github.com/akua-dev/akua) is the open-source packaging substrate behind Akua's per-installation renders. Every install on Akua is an akua Package: a typed, signed, deterministically-rendered KCL program that turns customer inputs into Kubernetes manifests.
You don't have to author an akua Package by hand to use Akua. For most products, Akua synthesizes one from your sources. But if you want full control over composition (sidecars, custom CRDs, multi-resource patches), authoring directly is supported.
## What akua provides
| Surface | Purpose |
| ----------------------------- | --------------------------------------------------------------------------------------- |
| **`package.k`** | Install composition: KCL logic that turns inputs into Kubernetes resources |
| **`akua.toml` + `akua.lock`** | Pinned dependencies (Helm charts, other Packages, KCL libraries) with cosign signatures |
| **`akua render`** | Executes the Package against customer inputs, produces deploy-ready manifests |
| **`akua export`** | Emits the Package's input schema as standards-pure JSON Schema 2020-12 / OpenAPI 3.1 |
A programmatic API exists for embedding akua in your own tooling. See the [akua repo](https://github.com/akua-dev/akua) for details.
## How Akua uses akua
Akua runs akua at three points in the install lifecycle:
1. **Schema for the install wizard**: Akua exports the Package's `Input` schema as JSON Schema; the wizard renders from it. UI hints from `@ui(...)` decorators flow through as `x-ui` extensions.
2. **Per-install rendering**: for every customer install, Akua renders the Package against the customer's `inputs.yaml`, vendoring upstream deps and writing the rendered manifests into the [installation repository](/installs/repositories).
3. **Update propagation**: when a Package version changes (composition, defaults, or pinned deps), Akua re-renders every affected installation independently.
## Where to start
Authoring `package.k`: the `Input` schema, `@ui` annotations, composition.
How `@ui` drives the install wizard at `/i/` and what offers carry.
Source code, full CLI reference, SDK docs, examples.
The per-install git repo that materializes a rendered Package.
## Status
Akua is **pre-alpha**. The Package format and CLI contract are stable enough to build on, but the CLI verb set is still iterating. Akua pins to a specific akua version per release and bumps deliberately.
For canonical, always-fresh references, the `akua` repository is authoritative. The pages here are curated for product authors building on akua within Akua; full architecture, embedded engines, security model, and roadmap docs live in the [akua docs directory](https://github.com/akua-dev/akua/tree/main/docs).
## Related topics
The per-install git repository that materializes a rendered Package.
How your Package's schema drives the install wizard.
Wizard, overrides, and reviewed repository changes.
Wrap a Package into a sellable product with billing.
# Package format
Source: https://docs.akua.dev/akua/package-format
Authoring an akua Package: the Input schema, @ui annotations, and composition
The canonical shape of an akua Package is a KCL program with three regions: imports, an `Input` schema, and a body that calls source engines (Helm, kustomize, RGD) and aggregates resources. This page is an Akua-focused excerpt of the [akua package format spec](https://github.com/akua-dev/akua/blob/main/docs/package-format.md). The full spec covers engine calls, lockfile, and metadata; this page focuses on what an Akua product author touches most: the Input schema and `@ui` annotations.
## Anatomy
Every Package is one KCL program with three typed regions:
```python theme={null}
# package.k
# (1) imports — engines, ambient context, schemas
import akua.ctx
import akua.helm
import charts.webapp as webapp
# (2) schema — the public input contract
schema Input:
appName: str
hostname: str
replicas: int = 3
input: Input = ctx.input()
# (3) body — engine calls + transforms + aggregation
_app = helm.template(webapp.Chart {
values = webapp.Values { replicaCount = input.replicas }
})
resources = _app
```
`akua render` writes every entry of `resources` as a YAML file under `--out`. Akua runs that render per-installation and commits the output to the [installation repository](/installs/repositories).
## The `Input` schema
The `Input` schema is the public contract: it declares what customers can configure. This schema is what Akua exports to JSON Schema for the install wizard.
Rules:
* The schema must be named `Input`. The binding line is canonically `input: Input = ctx.input()`.
* Fields use KCL native types: `str`, `int`, `float`, `bool`, `[T]`, `{str: T}`, unions (`"a" | "b" | "c"`), nested schemas.
* Fields without defaults are required; fields with defaults are optional.
* Use KCL docstrings (`"""..."""`) on each field; they become the JSON Schema `description` and surface in autocomplete and the install wizard.
* `check:` blocks express cross-field constraints; they run during render.
* No runtime side effects (no env, no filesystem, no network). KCL's sandbox enforces this.
Example with all shapes:
```python theme={null}
schema Input:
"""Public inputs for this package."""
appName: str
"""Application name. Lowercase, hyphen-separated."""
routing: RoutingInput
replicas: int = 3
"""Number of replicas. Minimum 1 in production."""
tier: "startup" | "production" = "startup"
additional_hosts: [HostInput] = []
labels: {str: str} = {}
check:
replicas >= 1, "replicas must be at least 1"
len(additional_hosts) < 10, "at most 10 additional hosts"
schema RoutingInput:
hostname: str
tls: bool = True
schema HostInput:
hostname: str
priority: int = 0
```
## `@ui` annotations
KCL docstrings carry the `description` field, but the install wizard needs more: field ordering, grouping into sections, widget hints, validation bounds. akua provides the `@ui(...)` decorator for this.
`@ui(...)` is an authoring hint that's stripped before the source reaches KCL's resolver and projected onto the JSON Schema property as the OpenAPI-3.1-compliant `x-ui` extension. Akua's install wizard recognizes `x-ui` and renders accordingly; renderers that don't, ignore it.
```python theme={null}
schema Input:
"""Public inputs for this package."""
@ui(order=10, group="Identity")
appName: str
"""Application name. Lowercase, hyphen-separated."""
@ui(order=20, group="Identity", placeholder="app.example.com")
hostname: str
"""Public hostname. Must be a valid RFC 1123 DNS name."""
@ui(order=30, group="Capacity", widget="slider", min=1, max=20)
replicas: int = 3
"""Number of replicas. Minimum 1 in production."""
@ui(order=40, group="Capacity")
tier: "startup" | "production" = "startup"
"""Resource tier."""
```
### Recognized keys
The keyword arguments to `@ui(...)` are arbitrary; anything you pass becomes `x-ui` metadata. Akua's wizard currently recognizes:
| Key | Effect |
| ------------- | ------------------------------------------------------------------------ |
| `order` | Numeric position within the form (lower = earlier) |
| `group` | Section header the field appears under (e.g. `"Identity"`, `"Capacity"`) |
| `widget` | Field renderer hint: `"slider"`, `"password"`, `"textarea"`, `"select"` |
| `placeholder` | Placeholder text shown in empty inputs |
| `min` / `max` | Numeric bounds (used by `widget="slider"` and form validation) |
Unknown keys are ignored, so you can add `@ui(foo=bar)` annotations for your own renderers without breaking Akua.
### How `@ui` reaches the wizard
```
package.k (with @ui annotations)
│
▼ schema export
JSON Schema with x-ui extensions
│
▼ cached per Package version
│
▼ fetched by /i/ install wizard
Form rendered with x-ui hints respected
```
See [Offers](/marketplace/offers) for the wizard side of this flow.
## Composition body
The body composes resources by calling engine functions:
```python theme={null}
# Helm with per-source input mapping
_app = helm.template(webapp.Chart {
values = webapp.Values {
replicaCount = input.replicas
ingress.hostname = input.hostname
}
})
# Add extra resources declared in KCL
_servicemonitor = {
apiVersion: "monitoring.coreos.com/v1"
kind: "ServiceMonitor"
metadata.name: input.appName
spec.selector.matchLabels.app: input.appName
}
resources = [*_app, _servicemonitor]
```
For the full body / engine-callable reference (Helm, kustomize, kro RGD, OCI fetch), see the [akua package format spec](https://github.com/akua-dev/akua/blob/main/docs/package-format.md#4-body--engine-calls--transforms).
## Exporting vs rendering
| Verb | Purpose | Needs inputs? | Output |
| ------------- | --------------------------------------------------------------------- | ------------- | ---------------------------------- |
| `akua export` | Convert the Package's `Input` schema to a standard interchange format | No | JSON Schema 2020-12 or OpenAPI 3.1 |
| `akua render` | Execute the Package's full pipeline against customer inputs | Yes | Rendered YAML manifests |
Akua exports the schema once per Package version (cached) to drive the install wizard, and renders once per install and again on every input change.
## Related topics
How `@ui` drives the install wizard.
How Packages, Products, and Installations relate.
Edit `inputs.yaml` and `package.k` directly.
Full spec: engines, lockfile, signing.
# Explain an access decision
Source: https://docs.akua.dev/api-reference/access-decisions/explain-an-access-decision
/openapi-public.json post /access_decisions
Explains whether the authenticated requester can perform an access action and why.
# List agent events
Source: https://docs.akua.dev/api-reference/agent-events/list-agent-events
/openapi-public.json get /agent_events
Lists normalized events for a workspace, session, or turn.
# Stream agent events
Source: https://docs.akua.dev/api-reference/agent-events/stream-agent-events
/openapi-public.json get /agent_events:stream
Streams normalized agent events as Server-Sent Events.
# Get agent preferences
Source: https://docs.akua.dev/api-reference/agent-preferences/get-agent-preferences
/openapi-public.json get /agent_preferences
Gets the current user's workspace-scoped agent preferences.
# Update agent preferences
Source: https://docs.akua.dev/api-reference/agent-preferences/update-agent-preferences
/openapi-public.json patch /agent_preferences
Updates the current user's workspace-scoped agent preferences.
# List agent provider exchanges
Source: https://docs.akua.dev/api-reference/agent-provider-exchanges/list-agent-provider-exchanges
/openapi-public.json get /agent_provider_exchanges
Lists redacted provider proxy request and response metadata for one agent turn.
# Archive agent session
Source: https://docs.akua.dev/api-reference/agent-sessions/archive-agent-session
/openapi-public.json delete /agent_sessions/{id}
Archives an agent session and requests runtime cleanup.
# Create agent session
Source: https://docs.akua.dev/api-reference/agent-sessions/create-agent-session
/openapi-public.json post /agent_sessions
Creates a durable workspace-scoped session for an agent.
# Detect agent work conflicts
Source: https://docs.akua.dev/api-reference/agent-sessions/detect-agent-work-conflicts
/openapi-public.json get /agent_sessions:detectConflicts
Finds active agent sessions that have already referenced the same repository, install, cluster, or repository change request.
# Get agent session
Source: https://docs.akua.dev/api-reference/agent-sessions/get-agent-session
/openapi-public.json get /agent_sessions/{id}
Gets one agent session.
# List agent sessions
Source: https://docs.akua.dev/api-reference/agent-sessions/list-agent-sessions
/openapi-public.json get /agent_sessions
Lists agent sessions in the workspace.
# Set agent session retention
Source: https://docs.akua.dev/api-reference/agent-sessions/set-agent-session-retention
/openapi-public.json post /agent_sessions/{id}:setRetention
Updates retained filesystem policy for an agent session.
# Get agent skill
Source: https://docs.akua.dev/api-reference/agent-skills/get-agent-skill
/openapi-public.json get /agent_skills/{id}
Gets one agent skill.
# List agent skills
Source: https://docs.akua.dev/api-reference/agent-skills/list-agent-skills
/openapi-public.json get /agent_skills
Lists published agent skills visible to the workspace.
# Get agent template
Source: https://docs.akua.dev/api-reference/agent-templates/get-agent-template
/openapi-public.json get /agent_templates/{id}
Gets one platform-curated agent template.
# List agent templates
Source: https://docs.akua.dev/api-reference/agent-templates/list-agent-templates
/openapi-public.json get /agent_templates
Lists platform-curated agent templates visible to the workspace.
# Cancel agent turn
Source: https://docs.akua.dev/api-reference/agent-turns/cancel-agent-turn
/openapi-public.json post /agent_turns/{id}:cancel
Cancels a running or queued agent turn.
# Emit agent turn event
Source: https://docs.akua.dev/api-reference/agent-turns/emit-agent-turn-event
/openapi-public.json post /agent_turns/{id}:emit
Emits a constrained event intent for a running agent turn.
# Get agent turn
Source: https://docs.akua.dev/api-reference/agent-turns/get-agent-turn
/openapi-public.json get /agent_turns/{id}
Gets one agent turn.
# List agent turns
Source: https://docs.akua.dev/api-reference/agent-turns/list-agent-turns
/openapi-public.json get /agent_turns
Lists agent turns in the workspace or one session.
# Submit agent turn
Source: https://docs.akua.dev/api-reference/agent-turns/submit-agent-turn
/openapi-public.json post /agent_turns
Submits one instruction to an agent session.
# Archive agent
Source: https://docs.akua.dev/api-reference/agents/archive-agent
/openapi-public.json delete /agents/{id}
Archives an agent and stops future ambient triggers.
# Create agent
Source: https://docs.akua.dev/api-reference/agents/create-agent
/openapi-public.json post /agents
Creates a durable workspace-scoped agent identity.
# Enable agent
Source: https://docs.akua.dev/api-reference/agents/enable-agent
/openapi-public.json post /agents/{id}:enable
Re-enables an archived agent so it can receive sessions and ambient triggers.
# Get agent
Source: https://docs.akua.dev/api-reference/agents/get-agent
/openapi-public.json get /agents/{id}
Gets one agent.
# List agents
Source: https://docs.akua.dev/api-reference/agents/list-agents
/openapi-public.json get /agents
Lists agents in the workspace.
# Update agent
Source: https://docs.akua.dev/api-reference/agents/update-agent
/openapi-public.json patch /agents/{id}
Updates mutable agent configuration. Lifecycle state changes use archive.
# Create an API token
Source: https://docs.akua.dev/api-reference/api-tokens/create-an-api-token
/openapi-public.json post /api_tokens
Creates a workspace API token. The full plaintext token is returned in the response and never shown again - store it securely.
# List API tokens
Source: https://docs.akua.dev/api-reference/api-tokens/list-api-tokens
/openapi-public.json get /api_tokens
Returns metadata for the workspace's API tokens. Full token values are never shown after creation.
# Revoke an API token
Source: https://docs.akua.dev/api-reference/api-tokens/revoke-an-api-token
/openapi-public.json delete /api_tokens/{id}
Revokes a workspace API token. The token immediately stops authenticating requests.
# List approval requests
Source: https://docs.akua.dev/api-reference/approval-requests/list-approval-requests
/openapi-public.json get /approval_requests
Lists pending and resolved approval requests in the workspace.
# Resolve approval request
Source: https://docs.akua.dev/api-reference/approval-requests/resolve-approval-request
/openapi-public.json post /approval_requests/{id}:resolve
Approves or rejects an approval request.
# Create Cloudflare credential
Source: https://docs.akua.dev/api-reference/cloudflare/create-cloudflare-credential
/openapi-public.json post /cloudflare_connections
Adds a Cloudflare API credential to the workspace. The API token is stored as a platform Secret and is never returned.
# Delete Cloudflare credential
Source: https://docs.akua.dev/api-reference/cloudflare/delete-cloudflare-credential
/openapi-public.json delete /cloudflare_connections/{id}
Permanently removes a Cloudflare credential. Active gateways using it must be deleted first.
# List Cloudflare credentials
Source: https://docs.akua.dev/api-reference/cloudflare/list-cloudflare-credentials
/openapi-public.json get /cloudflare_connections
Returns Cloudflare credentials for the workspace. API tokens are never exposed.
# Create cluster
Source: https://docs.akua.dev/api-reference/clusters/create-cluster
/openapi-public.json post /clusters
Creates a managed cluster and returns an async Operation envelope. State for in-flight operations is eventually consistent and may lag actual execution by a few seconds. State for completed operations (`done: true`) is immutable.
# Create worker bootstrap
Source: https://docs.akua.dev/api-reference/clusters/create-worker-bootstrap
/openapi-public.json post /clusters/{id}/worker_bootstraps
Issues a new worker-bootstrap row and returns its metadata.
# Delete cluster
Source: https://docs.akua.dev/api-reference/clusters/delete-cluster
/openapi-public.json delete /clusters/{id}
Tears down the cluster and all of its owned resources. Returns an Operation envelope; the actual teardown happens asynchronously. Caller must be a workspace owner.
# Execute command in cluster
Source: https://docs.akua.dev/api-reference/clusters/execute-command-in-cluster
/openapi-public.json post /clusters/{id}:exec
Runs a structured command in a pod and returns the result inline. No LRO wrapper by design.
# Get cluster
Source: https://docs.akua.dev/api-reference/clusters/get-cluster
/openapi-public.json get /clusters/{id}
Gets a cluster by id.
# Get cluster capabilities
Source: https://docs.akua.dev/api-reference/clusters/get-cluster-capabilities
/openapi-public.json get /clusters/{id}/capabilities
Gets the last observed Kubernetes capability snapshot for a cluster.
# Get cluster kubeconfig
Source: https://docs.akua.dev/api-reference/clusters/get-cluster-kubeconfig
/openapi-public.json get /clusters/{id}/kubeconfig
Returns cluster admin kubeconfig for workspace owners. R6 deliberate divergence retained with an audit-log requirement.
# Get cluster worker bootstrap
Source: https://docs.akua.dev/api-reference/clusters/get-cluster-worker-bootstrap
/openapi-public.json get /clusters/{id}/worker_bootstraps/{wbs_id}
Returns a single worker-bootstrap token by ID, including its current status and expiry timestamp.
# Import cluster
Source: https://docs.akua.dev/api-reference/clusters/import-cluster
/openapi-public.json post /clusters:import
Imports an existing cluster from kubeconfig.
# List cluster worker bootstraps
Source: https://docs.akua.dev/api-reference/clusters/list-cluster-worker-bootstraps
/openapi-public.json get /clusters/{id}/worker_bootstraps
Lists worker-bootstrap tokens for the cluster. Cursor-paginated. Includes revoked / expired tokens by default — filter via the `status` query when implemented.
# List clusters
Source: https://docs.akua.dev/api-reference/clusters/list-clusters
/openapi-public.json get /clusters
Lists clusters visible to the authenticated workspace owner.
# Proxy cluster API
Source: https://docs.akua.dev/api-reference/clusters/proxy-cluster-api
/openapi-public.json get /clusters/{id}/kube_proxy/{path:*}
Proxy kube-apiserver traffic through the public API. `path:*` is forwarded verbatim to upstream.
# Refresh cluster capabilities
Source: https://docs.akua.dev/api-reference/clusters/refresh-cluster-capabilities
/openapi-public.json post /clusters/{id}/capabilities:refresh
Refreshes observed cluster capability facts. The API returns an Operation envelope because cluster inspection runs asynchronously.
# Resume cluster
Source: https://docs.akua.dev/api-reference/clusters/resume-cluster
/openapi-public.json post /clusters/{id}:resume
Resumes a suspended cluster and returns an async Operation envelope.
# Revoke worker bootstrap
Source: https://docs.akua.dev/api-reference/clusters/revoke-worker-bootstrap
/openapi-public.json post /clusters/{id}/worker_bootstraps/{wbs_id}:revoke
Starts an asynchronous revoke of a worker bootstrap token. The bootstrap is soft-revoked immediately; k0s token invalidation completes when the managed control plane is reachable.
# Suspend cluster
Source: https://docs.akua.dev/api-reference/clusters/suspend-cluster
/openapi-public.json post /clusters/{id}:suspend
Suspends a running cluster. The API returns an Operation envelope because teardown and drain are asynchronous.
# Update cluster
Source: https://docs.akua.dev/api-reference/clusters/update-cluster
/openapi-public.json patch /clusters/{id}
Updates editable cluster fields.
# Check if machine has drifted
Source: https://docs.akua.dev/api-reference/compute/check-if-machine-has-drifted
/openapi-public.json get /compute/machines/{providerId}/drift
Checks if a machine has drifted from its desired compute configuration.
# Create a compute config
Source: https://docs.akua.dev/api-reference/compute/create-a-compute-config
/openapi-public.json post /compute/configs
# Create a machine
Source: https://docs.akua.dev/api-reference/compute/create-a-machine
/openapi-public.json post /compute/machines
Provisions a new machine in the specified cluster with the given compute configuration.
# Delete a compute config
Source: https://docs.akua.dev/api-reference/compute/delete-a-compute-config
/openapi-public.json delete /compute/configs/{id}
# Delete a machine
Source: https://docs.akua.dev/api-reference/compute/delete-a-machine
/openapi-public.json delete /compute/machines/{providerId}
Deletes a machine by provider ID. The node is drained before the cloud server is terminated.
# Delete a suspension
Source: https://docs.akua.dev/api-reference/compute/delete-a-suspension
/openapi-public.json delete /compute/suspensions/{id}
Deletes the snapshot and suspension record permanently.
# Get a compute config
Source: https://docs.akua.dev/api-reference/compute/get-a-compute-config
/openapi-public.json get /compute/configs/{id}
# Get cluster compute status
Source: https://docs.akua.dev/api-reference/compute/get-cluster-compute-status
/openapi-public.json get /clusters/{clusterId}/compute_status
Returns auto-scaling state, machine count, and limits for a cluster.
# Get machine status
Source: https://docs.akua.dev/api-reference/compute/get-machine-status
/openapi-public.json get /compute/machines/{providerId}
Returns current state of a machine including conditions and provider metadata.
# List available instance types
Source: https://docs.akua.dev/api-reference/compute/list-available-instance-types
/openapi-public.json get /compute/instance_types
Returns instance types with pricing for a compute config. Returns available instance types for provisioning. Results are cached.
# List compute configs
Source: https://docs.akua.dev/api-reference/compute/list-compute-configs
/openapi-public.json get /compute/configs
Lists compute configs for the workspace.
# List machines in cluster
Source: https://docs.akua.dev/api-reference/compute/list-machines-in-cluster
/openapi-public.json get /compute/machines
Lists all machines for a cluster.
# List suspended machines
Source: https://docs.akua.dev/api-reference/compute/list-suspended-machines
/openapi-public.json get /compute/suspensions
Lists all suspended machines for the workspace.
# Resume a suspended machine
Source: https://docs.akua.dev/api-reference/compute/resume-a-suspended-machine
/openapi-public.json post /compute/suspensions/{id}/resume
Restores the machine from its snapshot, creates a new cloud server.
# Suspend a machine
Source: https://docs.akua.dev/api-reference/compute/suspend-a-machine
/openapi-public.json post /compute/machines/{providerId}/suspend
Snapshots the machine disk, deletes the cloud server to stop billing, and creates a suspension record.
# Update cluster compute settings
Source: https://docs.akua.dev/api-reference/compute/update-cluster-compute-settings
/openapi-public.json patch /clusters/{clusterId}/compute_settings
Controls auto-scaling behavior and machine limits for a cluster.
# Create compute config
Source: https://docs.akua.dev/api-reference/computeconfigs/create-compute-config
/openapi-public.json post /compute_configs
Creates a compute config row.
# Delete compute config
Source: https://docs.akua.dev/api-reference/computeconfigs/delete-compute-config
/openapi-public.json delete /compute_configs/{id}
Deletes a compute config.
# Get compute config
Source: https://docs.akua.dev/api-reference/computeconfigs/get-compute-config
/openapi-public.json get /compute_configs/{id}
Returns a compute config by ID.
# List compute configs
Source: https://docs.akua.dev/api-reference/computeconfigs/list-compute-configs
/openapi-public.json get /compute_configs
Lists compute configs in the workspace.
# Update compute config
Source: https://docs.akua.dev/api-reference/computeconfigs/update-compute-config
/openapi-public.json patch /compute_configs/{id}
Updates mutable fields of a compute config.
# Create custom domain
Source: https://docs.akua.dev/api-reference/custom-domains/create-custom-domain
/openapi-public.json post /workspaces/{id}/custom_domains
Creates a custom domain and starts routing reconciliation.
# Delete custom domain
Source: https://docs.akua.dev/api-reference/custom-domains/delete-custom-domain
/openapi-public.json delete /workspaces/{id}/custom_domains/{custom_domain_id}
Starts a workflow that releases a custom domain.
# Get custom domain
Source: https://docs.akua.dev/api-reference/custom-domains/get-custom-domain
/openapi-public.json get /workspaces/{id}/custom_domains/{custom_domain_id}
Returns one custom domain belonging to a workspace.
# List custom domains
Source: https://docs.akua.dev/api-reference/custom-domains/list-custom-domains
/openapi-public.json get /workspaces/{id}/custom_domains
Lists custom domains belonging to a workspace.
# Update custom domain
Source: https://docs.akua.dev/api-reference/custom-domains/update-custom-domain
/openapi-public.json patch /workspaces/{id}/custom_domains/{custom_domain_id}
Updates mutable custom domain routing settings.
# Create dashboard
Source: https://docs.akua.dev/api-reference/dashboards/create-dashboard
/openapi-public.json post /dashboards
Creates a dashboard in the workspace. Widgets are added through the dashboard widgets sub-collection.
# Create dashboard widget
Source: https://docs.akua.dev/api-reference/dashboards/create-dashboard-widget
/openapi-public.json post /dashboards/{id}/widgets
Creates a widget as a child resource under a dashboard.
# Delete dashboard
Source: https://docs.akua.dev/api-reference/dashboards/delete-dashboard
/openapi-public.json delete /dashboards/{id}
Permanently deletes a dashboard. Referenced snippets are not affected.
# Delete dashboard widget
Source: https://docs.akua.dev/api-reference/dashboards/delete-dashboard-widget
/openapi-public.json delete /dashboards/{id}/widgets/{wgt_id}
Deletes a dashboard widget. Snippet references are preserved.
# Get dashboard details
Source: https://docs.akua.dev/api-reference/dashboards/get-dashboard-details
/openapi-public.json get /dashboards/{id}
Returns a dashboard including its widget layout and snippet references.
# Get dashboard widget
Source: https://docs.akua.dev/api-reference/dashboards/get-dashboard-widget
/openapi-public.json get /dashboards/{id}/widgets/{wgt_id}
Returns a single dashboard widget.
# List dashboard widgets
Source: https://docs.akua.dev/api-reference/dashboards/list-dashboard-widgets
/openapi-public.json get /dashboards/{id}/widgets
Lists widgets for a dashboard.
# List dashboards in workspace
Source: https://docs.akua.dev/api-reference/dashboards/list-dashboards-in-workspace
/openapi-public.json get /dashboards
Returns all dashboards belonging to the workspace specified in the workspace context.
# Update dashboard
Source: https://docs.akua.dev/api-reference/dashboards/update-dashboard
/openapi-public.json patch /dashboards/{id}
Update dashboard metadata. Widget mutations use the `/widgets` sub-collection.
# Update dashboard widget
Source: https://docs.akua.dev/api-reference/dashboards/update-dashboard-widget
/openapi-public.json patch /dashboards/{id}/widgets/{wgt_id}
Updates widget placement and display settings.
# List entitlements
Source: https://docs.akua.dev/api-reference/entitlements/list-entitlements
/openapi-public.json get /entitlements
Returns active effective entitlements visible to the authenticated caller.
# Create install
Source: https://docs.akua.dev/api-reference/installs/create-install
/openapi-public.json post /installs
Creates a product-based or direct installation. Akua processes the installation in the background and returns an Operation envelope to poll for progress.
# Create install render
Source: https://docs.akua.dev/api-reference/installs/create-install-render
/openapi-public.json post /installs/{id}/renders
Starts a render attempt and records the resulting render artifact metadata.
# Delete install
Source: https://docs.akua.dev/api-reference/installs/delete-install
/openapi-public.json delete /installs/{id}
Deletes an install and cascades resource cleanup asynchronously. Returns an Operation envelope to poll for progress.
# Get install details
Source: https://docs.akua.dev/api-reference/installs/get-install-details
/openapi-public.json get /installs/{id}
Returns current install metadata.
# Get install render
Source: https://docs.akua.dev/api-reference/installs/get-install-render
/openapi-public.json get /installs/{id}/renders/{render_id}
Returns a single render artifact.
# Get install status
Source: https://docs.akua.dev/api-reference/installs/get-install-status
/openapi-public.json get /installs/{id}/status
Returns the live install deploy status for dashboards and health checks.
# List install pods
Source: https://docs.akua.dev/api-reference/installs/list-install-pods
/openapi-public.json get /installs/{id}/pods
Returns current pod names and containers for the install.
# List install renders
Source: https://docs.akua.dev/api-reference/installs/list-install-renders
/openapi-public.json get /installs/{id}/renders
Lists render artifacts for an install.
# List installs
Source: https://docs.akua.dev/api-reference/installs/list-installs
/openapi-public.json get /installs
Lists installs in the current workspace. With `product_id`, lists installs attributed to that product for product-owner support visibility.
# Stream install logs
Source: https://docs.akua.dev/api-reference/installs/stream-install-logs
/openapi-public.json get /installs/{id}/logs
Streams log output for an install via Server-Sent Events. Use `Accept: text/event-stream`.
# Create machine
Source: https://docs.akua.dev/api-reference/machines/create-machine
/openapi-public.json post /machines
Creates a machine and returns a long-running operation envelope.
# Create machine drift report
Source: https://docs.akua.dev/api-reference/machines/create-machine-drift-report
/openapi-public.json post /machines/{id}/drift_reports
Runs drift detection and stores a dedicated report row.
# Delete machine
Source: https://docs.akua.dev/api-reference/machines/delete-machine
/openapi-public.json delete /machines/{id}
Deletes a machine and returns a long-running operation envelope.
# Get machine
Source: https://docs.akua.dev/api-reference/machines/get-machine
/openapi-public.json get /machines/{id}
Returns a machine by ID.
# Get machine drift report
Source: https://docs.akua.dev/api-reference/machines/get-machine-drift-report
/openapi-public.json get /machines/{id}/drift_reports/{report_id}
Returns a single drift report by ID.
# Get machine suspension event
Source: https://docs.akua.dev/api-reference/machines/get-machine-suspension-event
/openapi-public.json get /machines/{id}/suspension_events/{event_id}
Returns a single suspension event for a machine, including snapshot reference, cost, lifecycle state, and timing details.
# List machine drift reports
Source: https://docs.akua.dev/api-reference/machines/list-machine-drift-reports
/openapi-public.json get /machines/{id}/drift_reports
Lists historical drift reports for a machine.
# List machine suspension events
Source: https://docs.akua.dev/api-reference/machines/list-machine-suspension-events
/openapi-public.json get /machines/{id}/suspension_events
Lists historical suspension events for the machine. Events record suspend, resume, expiry, and snapshot-cost details for audit and billing reports.
# List machines
Source: https://docs.akua.dev/api-reference/machines/list-machines
/openapi-public.json get /machines
Lists all machines in the workspace.
# Resume machine
Source: https://docs.akua.dev/api-reference/machines/resume-machine
/openapi-public.json post /machines/{id}:resume
Resumes a suspended machine and returns a long-running operation envelope. The machine ID stays stable, but provider_resource.public_ip can change after resume on providers that recycle instances during suspension.
# Suspend machine
Source: https://docs.akua.dev/api-reference/machines/suspend-machine
/openapi-public.json post /machines/{id}:suspend
Suspends a machine and returns a long-running operation envelope. On providers that recycle instances during suspension, the machine ID stays stable but the public IP usually changes on resume unless a floating IP is attached.
# Update machine
Source: https://docs.akua.dev/api-reference/machines/update-machine
/openapi-public.json patch /machines/{id}
Updates machine metadata.
# Count unread notifications
Source: https://docs.akua.dev/api-reference/notifications/count-unread-notifications
/openapi-public.json get /notifications/unread_count
Returns the number of unread in-app notifications for the authenticated user.
# List recent notifications
Source: https://docs.akua.dev/api-reference/notifications/list-recent-notifications
/openapi-public.json get /notifications
Returns the authenticated user's most recent in-app notifications (max 50, newest first). Pass `unread=true` to filter to unread notifications only.
# Mark a notification as read
Source: https://docs.akua.dev/api-reference/notifications/mark-a-notification-as-read
/openapi-public.json patch /notifications/{id}/read
Marks a single notification as read. Idempotent: calls for already-read or unowned notifications succeed without effect.
# Mark all notifications as read
Source: https://docs.akua.dev/api-reference/notifications/mark-all-notifications-as-read
/openapi-public.json post /notifications/mark_all_read
Marks every unread in-app notification for the authenticated user as read. Idempotent.
# Archive offer
Source: https://docs.akua.dev/api-reference/offers/archive-offer
/openapi-public.json post /offers/{id}:archive
Archives the offer and blocks new redemptions. The offer row remains for history and audit; callers receive the full Offer with `status: "archived"`. Idempotent: already-archived offers return unchanged. If-Match is required for optimistic concurrency.
# Create offer
Source: https://docs.akua.dev/api-reference/offers/create-offer
/openapi-public.json post /offers
Creates an Offer for a product or a specific package version. When `product_id` is supplied without `package_version_id`, the server resolves the product’s current package version pin, validates `field_values` against that resolved version’s input schema, and stores the concrete package version on the Offer. Customers reach the Offer at `/i/` to start an install. When `allowed_emails` is non-empty, only those email addresses can use the Offer; when empty or omitted, any authenticated customer can.
# Get offer details
Source: https://docs.akua.dev/api-reference/offers/get-offer-details
/openapi-public.json get /offers/{id}
Returns the full offer record including pre-fill values and email allowlist. Caller must be a member of the offer’s workspace.
# List offers in workspace
Source: https://docs.akua.dev/api-reference/offers/list-offers-in-workspace
/openapi-public.json get /offers
Returns offers belonging to the workspace specified in the workspace context, newest first.
# Resolve offer by short hash
Source: https://docs.akua.dev/api-reference/offers/resolve-offer-by-short-hash
/openapi-public.json get /offers:resolve
Resolves an offer from the customer-clicked URL `/i/`. Anonymous callers receive the publicly-safe subset of fields needed to render the landing page (product name, logo, seller name, status, tier). Authenticated callers whose verified email matches the offer's allowlist additionally receive pre-fill values and other workspace-private fields. Authenticated callers whose email is not on the allowlist receive 403.
# Unarchive offer
Source: https://docs.akua.dev/api-reference/offers/unarchive-offer
/openapi-public.json post /offers/{id}:unarchive
Reverts a previously-archived offer back to `active`. Idempotent: already-active offers return unchanged. Does not auto-cascade to dependents or previously-archived child references.
# Get operation details + steps
Source: https://docs.akua.dev/api-reference/operations/get-operation-details-+-steps
/openapi-public.json get /operations/{id}
Returns the operation row plus its per-step progress events. Clients poll this endpoint while `done` is false; when `done` flips true, `response` carries the typed result (`SUCCEEDED`) or `error.message` carries the failure reason. Prefer `POST /v1/operations/{id}:wait` for sync "wait until done" semantics — it long-polls server-side instead of asking the client to tight-poll.
State for in-flight operations is eventually consistent — may lag actual execution by a few seconds. State for completed operations (`done: true`) is immutable.
# List operations
Source: https://docs.akua.dev/api-reference/operations/list-operations
/openapi-public.json get /operations
Workspace-scoped list of long-running operations, newest first. Without filters returns every operation in the workspace; with `?owner_type=install&owner_id=` narrows to a single entity.
State for in-flight operations is eventually consistent — may lag actual execution by a few seconds. State for completed operations (`done: true`) is immutable.
# Request operation cancellation
Source: https://docs.akua.dev/api-reference/operations/request-operation-cancellation
/openapi-public.json post /operations/{id}:cancel
Requests cancellation of an in-flight operation. Cancellation is asynchronous: successful requests return the current operation envelope while the worker drains the current step before settling into a terminal result. Replaying the request with the same Idempotency-Key is supported. If the operation has already reached a terminal state, cancellation is rejected with Unprocessable Entity.
When accepted, the operation is not cancelled instantly; it transitions through the normal cancellation flow and may still report progress for a short time.
# Wait for an operation to reach a terminal state
Source: https://docs.akua.dev/api-reference/operations/wait-for-an-operation-to-reach-a-terminal-state
/openapi-public.json post /operations/{id}:wait
Long-polls server-side until the operation reaches a terminal state (`SUCCEEDED`, `FAILED`, `CANCELLED`) or the timeout elapses. Returns the latest `Operation` either way — check `done` to distinguish.
Server-side this is a live subscription on the operation row, not a polling loop, so the response fires within milliseconds of the workflow reaching its terminal state.
State for in-flight operations is eventually consistent — may lag actual execution by a few seconds. State for completed operations (`done: true`) is immutable.
# Cancel order draft
Source: https://docs.akua.dev/api-reference/order-drafts/cancel-order-draft
/openapi-public.json post /order_drafts/{id}:cancel
Terminates an in-flight order draft, returning the updated record. Allowed for the order draft’s own customer or any member of the parent offer’s workspace. Idempotent — cancelling a terminated order draft returns it unchanged. Allocated cluster resources are released and any in-flight install workflow is terminated; previously-completed work is NOT undone.
# Claim order draft
Source: https://docs.akua.dev/api-reference/order-drafts/claim-order-draft
/openapi-public.json post /order_drafts/{id}:claim
Binds the calling authenticated user to an anonymous order draft using a one-time claim token (R13 + AIP-147 INPUT_ONLY).
# Create order draft
Source: https://docs.akua.dev/api-reference/order-drafts/create-order-draft
/openapi-public.json post /offers/{offer}/order_drafts
Creates a customer wizard session (OrderDraft) for the parent offer. The caller is the customer; their authenticated user becomes the draft's owner. Each idempotent create call returns the same draft for the same Idempotency-Key. Concurrency limits and email-allowlist gates apply per the offer's configuration; failures map to 403 (forbidden) or 422 (offer not redeemable).
# Create order draft checkout session
Source: https://docs.akua.dev/api-reference/order-drafts/create-order-draft-checkout-session
/openapi-public.json post /order_drafts/{id}/checkout_sessions
Creates a Stripe Checkout Session for the current order-draft payment revision, or returns the existing open session when it still has enough remaining lifetime. Stale sessions are expired and superseded before a replacement is created.
# Create order draft worker bootstrap
Source: https://docs.akua.dev/api-reference/order-drafts/create-order-draft-worker-bootstrap
/openapi-public.json post /order_drafts/{id}:createWorkerBootstrap
Creates a short-lived worker bootstrap token and renders command/cloud-init data for the cluster allocated to this order draft. Only valid while the draft is waiting for compute bootstrap.
# Get order draft checkout session
Source: https://docs.akua.dev/api-reference/order-drafts/get-order-draft-checkout-session
/openapi-public.json get /order_drafts/{id}/checkout_sessions/{chk_id}
Returns one historical checkout session by ID, including the current session state.
# Get order draft details
Source: https://docs.akua.dev/api-reference/order-drafts/get-order-draft-details
/openapi-public.json get /order_drafts/{id}
Returns the order draft row. The order draft’s own customer sees the full record including `field_values`; workspace members of the parent offer see the row with `field_values` omitted.
# List order draft checkout sessions
Source: https://docs.akua.dev/api-reference/order-drafts/list-order-draft-checkout-sessions
/openapi-public.json get /order_drafts/{id}/checkout_sessions
Returns historical checkout session rows for the order draft (current and past) for resume/audit workflows.
# List order drafts
Source: https://docs.akua.dev/api-reference/order-drafts/list-order-drafts
/openapi-public.json get /order_drafts
Returns order drafts for one offer. `?offer=` is required in v1; `?status=` can further filter by wizard phase. With a workspace context (token-implied or `Akua-Context`), only workspace-member-visible drafts are returned and `field_values` is omitted.
# Select order workspace
Source: https://docs.akua.dev/api-reference/order-drafts/select-order-workspace
/openapi-public.json post /order_drafts/{id}:selectWorkspace
Selects the customer workspace for an order draft, or creates a new workspace for the order. This advances the draft from workspace selection to compute allocation.
# Submit configure values
Source: https://docs.akua.dev/api-reference/order-drafts/submit-configure-values
/openapi-public.json post /order_drafts/{id}:submitConfiguration
Persists the customer’s configure-form values on the order draft and advances it to the payment phase, returning the updated record. Values are validated against the package version’s schema.
# Add organization member
Source: https://docs.akua.dev/api-reference/organizations/add-organization-member
/openapi-public.json post /organizations/{id}/members
Adds a user to the organization with the supplied role (defaults to `member`). Requires owner or admin role.
# Create organization
Source: https://docs.akua.dev/api-reference/organizations/create-organization
/openapi-public.json post /organizations
Creates a new organization. The authenticated user becomes the initial owner.
# Delete organization
Source: https://docs.akua.dev/api-reference/organizations/delete-organization
/openapi-public.json delete /organizations/{id}
Deletes an organization after validating membership, workspace ownership, and owner protection.
# Get organization details
Source: https://docs.akua.dev/api-reference/organizations/get-organization-details
/openapi-public.json get /organizations/{id}
Returns details for an organization the authenticated user belongs to.
# List managed workspaces
Source: https://docs.akua.dev/api-reference/organizations/list-managed-workspaces
/openapi-public.json get /organizations/{id}/workspaces
Lists workspaces managed by this organization. Requires membership in the organization.
# List organization members
Source: https://docs.akua.dev/api-reference/organizations/list-organization-members
/openapi-public.json get /organizations/{id}/members
Lists every member of the organization. Requires membership in the organization.
# List organizations
Source: https://docs.akua.dev/api-reference/organizations/list-organizations
/openapi-public.json get /organizations
Lists all organizations the authenticated user belongs to.
# Remove organization member
Source: https://docs.akua.dev/api-reference/organizations/remove-organization-member
/openapi-public.json delete /organizations/{id}/members/{userId}
Removes a member from the organization. Self-removal is always allowed; removing other users requires owner or admin role. The last owner cannot be removed.
# Update member role
Source: https://docs.akua.dev/api-reference/organizations/update-member-role
/openapi-public.json patch /organizations/{id}/members/{userId}
Updates the role of an existing member. Only the organization's owner may change roles.
# Update organization
Source: https://docs.akua.dev/api-reference/organizations/update-organization
/openapi-public.json patch /organizations/{id}
Updates profile fields on an organization. Requires owner or admin role in the organization.
# Create package
Source: https://docs.akua.dev/api-reference/packages/create-package
/openapi-public.json post /packages
Creates a package from one OCI Helm source as a long-running operation.
# Create package version
Source: https://docs.akua.dev/api-reference/packages/create-package-version
/openapi-public.json post /packages/{id}/versions
Registers an immutable version for an existing OCI-backed package. Akua verifies the supplied version metadata against the published artifact before durable registration. Requires published Package import access. Hosted packages publish versions through the package creation workflow.
# Delete package
Source: https://docs.akua.dev/api-reference/packages/delete-package
/openapi-public.json delete /packages/{id}
Deletes a Package and its PackageVersions only when no Product references the Package and no Install references any PackageVersion.
# Get package details
Source: https://docs.akua.dev/api-reference/packages/get-package-details
/openapi-public.json get /packages/{id}
Returns a single package and the `latest_version_id` pointer for this workspace.
# Get package version details
Source: https://docs.akua.dev/api-reference/packages/get-package-version-details
/openapi-public.json get /packages/{id}/versions/{version_id}
Returns a single version entry for a package.
# Get package version input schema
Source: https://docs.akua.dev/api-reference/packages/get-package-version-input-schema
/openapi-public.json get /packages/{id}/versions/{version_id}/inputs
Returns the version input schema used by the install wizard, typically generated JSON Schema.
# Import published package
Source: https://docs.akua.dev/api-reference/packages/import-published-package
/openapi-public.json post /packages:import
Imports a published OCI-backed Akua package and registers its first immutable version. Akua verifies the supplied version metadata against the published artifact before durable registration. Requires published Package import access.
# List package versions
Source: https://docs.akua.dev/api-reference/packages/list-package-versions
/openapi-public.json get /packages/{id}/versions
Returns published versions of a package, newest first.
# List packages
Source: https://docs.akua.dev/api-reference/packages/list-packages
/openapi-public.json get /packages
Returns all packages in the active workspace.
# Resolve Artifact Hub chart values + schema
Source: https://docs.akua.dev/api-reference/packages/resolve-artifact-hub-chart-values-+-schema
/openapi-public.json get /packages/artifacthub/{package_id}/versions/{version}/values_schema
Fetches a chart's values from Artifact Hub and returns them with a JSON Schema — the chart's published schema (when present) merged over a schema inferred from the values, so the editor always has defaults to show.
# Bind floating preview hostname
Source: https://docs.akua.dev/api-reference/preview-hostnames/bind-floating-preview-hostname
/openapi-public.json post /installs/{id}/preview_hostnames:bindFloating
Starts a workflow that binds or rebinds a stable preview hostname track.
# Bind pinned preview hostname
Source: https://docs.akua.dev/api-reference/preview-hostnames/bind-pinned-preview-hostname
/openapi-public.json post /installs/{id}/preview_hostnames:bindPinned
Starts a workflow that binds an immutable preview hostname to one render.
# Delete preview hostname
Source: https://docs.akua.dev/api-reference/preview-hostnames/delete-preview-hostname
/openapi-public.json delete /installs/{id}/preview_hostnames/{preview_hostname_id}
Starts a workflow that releases a preview hostname.
# Get preview hostname
Source: https://docs.akua.dev/api-reference/preview-hostnames/get-preview-hostname
/openapi-public.json get /installs/{id}/preview_hostnames/{preview_hostname_id}
Returns one preview hostname belonging to an install.
# List preview hostnames
Source: https://docs.akua.dev/api-reference/preview-hostnames/list-preview-hostnames
/openapi-public.json get /installs/{id}/preview_hostnames
Lists preview hostnames belonging to an install.
# Archive product
Source: https://docs.akua.dev/api-reference/products/archive-product
/openapi-public.json post /products/{id}:archive
Archives the product and removes it from active marketplace listings. The row persists with state `archived` for audit/history/revenue-attribution. Active installs and past orders are unaffected; backing packages remain independently managed and unchanged. Dashboard callers can still render historical product context.
# Create product
Source: https://docs.akua.dev/api-reference/products/create-product
/openapi-public.json post /products
Creates a Product backed by an existing Package and package version pin. Package source import belongs to the Packages API.
# Get product details
Source: https://docs.akua.dev/api-reference/products/get-product-details
/openapi-public.json get /products/{id}
Returns product metadata including the backing Package and marketplace settings.
# List products in workspace
Source: https://docs.akua.dev/api-reference/products/list-products-in-workspace
/openapi-public.json get /products
Returns all products belonging to the workspace specified in the workspace context.
# Unarchive product
Source: https://docs.akua.dev/api-reference/products/unarchive-product
/openapi-public.json post /products/{id}:unarchive
Restores a previously-archived product to `active`. The row remains in place and history is preserved. Active installs continue; dependent offers stay untouched unless separately unarchived.
# Update product
Source: https://docs.akua.dev/api-reference/products/update-product
/openapi-public.json patch /products/{id}
Updates Product metadata, marketplace listing state, and the package version pin for future offers and installs.
# Get quota usage for a specific metric
Source: https://docs.akua.dev/api-reference/quotas/get-quota-usage-for-a-specific-metric
/openapi-public.json get /quotas/{metric}
Returns current usage and limit for a single quota metric. The metric must be URL-encoded (e.g. `compute%2Fmachines`).
# List quota usage for the authenticated user
Source: https://docs.akua.dev/api-reference/quotas/list-quota-usage-for-the-authenticated-user
/openapi-public.json get /quotas
Returns current usage and limits for all quota metrics. Allocation and rate quotas are per-user across all workspaces. Concurrency quotas are per-cluster — pass `cluster_id` to include them.
# Create region
Source: https://docs.akua.dev/api-reference/regions/create-region
/openapi-public.json post /regions
Creates a named region in the workspace. Regions group clusters geographically for marketplace display.
# List regions in workspace
Source: https://docs.akua.dev/api-reference/regions/list-regions-in-workspace
/openapi-public.json get /regions
Returns all regions belonging to the workspace specified in the workspace context.
# Create registry credential
Source: https://docs.akua.dev/api-reference/registry/create-registry-credential
/openapi-public.json post /registry_connections
Adds a registry credential to the workspace for OCI proxy authentication.
# Delete registry credential
Source: https://docs.akua.dev/api-reference/registry/delete-registry-credential
/openapi-public.json delete /registry_connections/{id}
Permanently removes a registry credential. Active installs using this credential may lose pull access.
# List registry credentials
Source: https://docs.akua.dev/api-reference/registry/list-registry-credentials
/openapi-public.json get /registry_connections
Returns credentials for the workspace. Credential secrets are never exposed.
# Get repository details
Source: https://docs.akua.dev/api-reference/repositories/get-repository-details
/openapi-public.json get /repositories/{id}
Returns a single repository as a discriminated union per `purpose`; the shape varies by lifecycle.
# List repositories in workspace
Source: https://docs.akua.dev/api-reference/repositories/list-repositories-in-workspace
/openapi-public.json get /repositories
Lists repositories visible in the workspace. Filterable by `purpose` (deploy / package / repository_change_request). Wire IDs prefixed `repo_...`. Cursor-paginated.
# Accept repository change request
Source: https://docs.akua.dev/api-reference/repository-change-requests/accept-repository-change-request
/openapi-public.json post /repository_change_requests/{id}:accept
Validates and merges a repository change request into its parent repository.
# Create repository change request
Source: https://docs.akua.dev/api-reference/repository-change-requests/create-repository-change-request
/openapi-public.json post /repository_change_requests
Creates a fork-backed repository change request. Fork write credentials are minted separately.
# Create repository change request token
Source: https://docs.akua.dev/api-reference/repository-change-requests/create-repository-change-request-token
/openapi-public.json post /repository_change_requests/{id}:createToken
Mints short-lived credentials for pushing changes to the fork repository.
# Get repository change request
Source: https://docs.akua.dev/api-reference/repository-change-requests/get-repository-change-request
/openapi-public.json get /repository_change_requests/{id}
Returns one fork-backed repository change request.
# List repository change requests
Source: https://docs.akua.dev/api-reference/repository-change-requests/list-repository-change-requests
/openapi-public.json get /repository_change_requests
Lists fork-backed repository change requests in the active workspace.
# Reject repository change request
Source: https://docs.akua.dev/api-reference/repository-change-requests/reject-repository-change-request
/openapi-public.json post /repository_change_requests/{id}:reject
Rejects a repository change request and records the reason.
# Withdraw repository change request
Source: https://docs.akua.dev/api-reference/repository-change-requests/withdraw-repository-change-request
/openapi-public.json post /repository_change_requests/{id}:withdraw
Withdraws an editable repository change request and purges its fork.
# Access secret version plaintext
Source: https://docs.akua.dev/api-reference/secrets/access-secret-version-plaintext
/openapi-public.json post /secrets/{id}/versions/{vid}:access
Returns the plaintext value for an active secret version and writes an audit-log entry. Soft-deleted secrets return 404 until restored with :undelete.
# Create secret
Source: https://docs.akua.dev/api-reference/secrets/create-secret
/openapi-public.json post /secrets
Creates a workspace-scoped Secret with metadata and the first version. The plaintext value is consumed and never echoed.
# Create secret version
Source: https://docs.akua.dev/api-reference/secrets/create-secret-version
/openapi-public.json post /secrets/{id}/versions
Appends a new immutable SecretVersion. Plaintext is never echoed.
# Delete secret
Source: https://docs.akua.dev/api-reference/secrets/delete-secret
/openapi-public.json delete /secrets/{id}
Soft-deletes a secret and keeps version payloads recoverable until purge_at. Use force=true to immediately destroy version payloads.
# Destroy secret version
Source: https://docs.akua.dev/api-reference/secrets/destroy-secret-version
/openapi-public.json post /secrets/{id}/versions/{vid}:destroy
Irreversibly destroys a secret version payload and keeps metadata for audit.
# Disable secret version
Source: https://docs.akua.dev/api-reference/secrets/disable-secret-version
/openapi-public.json post /secrets/{id}/versions/{vid}:disable
Marks a secret version as disabled.
# Enable a disabled secret version
Source: https://docs.akua.dev/api-reference/secrets/enable-a-disabled-secret-version
/openapi-public.json post /secrets/{id}/versions/{vid}:enable
Re-enables a disabled SecretVersion. The newly-enabled version becomes eligible for `:access` calls again. Idempotent: enabling an already-enabled version returns 200 with no state change. Returns 409 ABORTED with a stale-revision hint if If-Match mismatches. Returns 409 if the version has been destroyed (irreversible).
# Get secret
Source: https://docs.akua.dev/api-reference/secrets/get-secret
/openapi-public.json get /secrets/{id}
Returns secret metadata. Plaintext values are never returned.
# Get secret version
Source: https://docs.akua.dev/api-reference/secrets/get-secret-version
/openapi-public.json get /secrets/{id}/versions/{vid}
Returns metadata for one secret version. Plaintext is never returned.
# List secret versions
Source: https://docs.akua.dev/api-reference/secrets/list-secret-versions
/openapi-public.json get /secrets/{id}/versions
Lists secret versions. Metadata only; plaintext values are never returned.
# List secrets
Source: https://docs.akua.dev/api-reference/secrets/list-secrets
/openapi-public.json get /secrets
Lists workspace secrets. Metadata only; plaintext values are never returned.
# Restore a soft-deleted secret
Source: https://docs.akua.dev/api-reference/secrets/restore-a-soft-deleted-secret
/openapi-public.json post /secrets/{id}:undelete
Restores a Secret that was soft-deleted via DELETE /v1/secrets/{id}, provided the call happens before its purge_at deadline. The Secret returns to state=active and its retained version payloads become accessible again. Returns 409 ABORTED on stale If-Match. Returns 404 if the secret was hard-deleted (force=true on DELETE) or has been purged.
# Update secret
Source: https://docs.akua.dev/api-reference/secrets/update-secret
/openapi-public.json patch /secrets/{id}
Updates secret metadata only. Rotate values with POST /secrets/{id}/versions.
# Validate a provider token
Source: https://docs.akua.dev/api-reference/secrets/validate-a-provider-token
/openapi-public.json post /secrets/validate_token
Probes a customer-supplied cloud-provider API token with a cheap read-only call to confirm it authenticates, without storing it. Use before creating a `cloud_provider/*` secret.
# Create snippet
Source: https://docs.akua.dev/api-reference/snippets/create-snippet
/openapi-public.json post /snippets
Creates a reusable code snippet in the workspace. Snippets are async JavaScript functions executed in a sandboxed runtime with access to platform.request() for API calls.
# Create snippet run
Source: https://docs.akua.dev/api-reference/snippets/create-snippet-run
/openapi-public.json post /snippets/{id}/runs
Creates a new snippet run resource under a snippet and starts execution. Idempotent with Idempotency-Key; callers receive the created run resource and Location header.
# Delete snippet
Source: https://docs.akua.dev/api-reference/snippets/delete-snippet
/openapi-public.json delete /snippets/{id}
Permanently deletes a snippet. Fails with 409 if the snippet is referenced by any dashboard widgets.
# Execute ad-hoc snippet code
Source: https://docs.akua.dev/api-reference/snippets/execute-ad-hoc-snippet-code
/openapi-public.json post /snippets:execute
Executes ad-hoc JavaScript in the snippet sandbox and returns the synchronous result. Does not persist a snippet or run resource.
# Execute stored snippet
Source: https://docs.akua.dev/api-reference/snippets/execute-stored-snippet
/openapi-public.json post /snippets/{id}:execute
Fetches a stored snippet by ID server-side, executes its code in the snippet sandbox, and returns the synchronous result.
# Get snippet dashboard usage
Source: https://docs.akua.dev/api-reference/snippets/get-snippet-dashboard-usage
/openapi-public.json get /snippets/{id}:usage
Returns dashboard references for one snippet.
# Get snippet details
Source: https://docs.akua.dev/api-reference/snippets/get-snippet-details
/openapi-public.json get /snippets/{id}
Returns a snippet including its code and display type.
# Get snippet run
Source: https://docs.akua.dev/api-reference/snippets/get-snippet-run
/openapi-public.json get /snippets/{id}/runs/{run_id}
Returns a single snippet run by ID.
# List snippet dashboard usage in workspace
Source: https://docs.akua.dev/api-reference/snippets/list-snippet-dashboard-usage-in-workspace
/openapi-public.json get /snippets:usage
Returns dashboard references for snippets in the workspace specified in the workspace context.
# List snippet runs
Source: https://docs.akua.dev/api-reference/snippets/list-snippet-runs
/openapi-public.json get /snippets/{id}/runs
Returns runs for a snippet. Use `view=basic` for a compact listing.
# List snippets in workspace
Source: https://docs.akua.dev/api-reference/snippets/list-snippets-in-workspace
/openapi-public.json get /snippets
Returns all snippets belonging to the workspace specified in the workspace context.
# Update snippet
Source: https://docs.akua.dev/api-reference/snippets/update-snippet
/openapi-public.json patch /snippets/{id}
Updates snippet properties. Only provided fields are changed. Dashboards using this snippet will pick up code changes on next run.
# Get workspace subdomain
Source: https://docs.akua.dev/api-reference/workspace-subdomains/get-workspace-subdomain
/openapi-public.json get /workspaces/{id}/subdomain
Returns the singleton workspace subdomain resource.
# Set workspace subdomain name
Source: https://docs.akua.dev/api-reference/workspace-subdomains/set-workspace-subdomain-name
/openapi-public.json post /workspaces/{id}/subdomain:setName
Starts the workspace subdomain rename workflow.
# Add workspace member
Source: https://docs.akua.dev/api-reference/workspaces/add-workspace-member
/openapi-public.json post /workspaces/{id}/members
Adds a user to a workspace with the requested role.
# Cancel workspace subscription
Source: https://docs.akua.dev/api-reference/workspaces/cancel-workspace-subscription
/openapi-public.json post /workspaces/{id}/subscription:cancel
Cancels or schedules cancellation for a workspace subscription.
# Change workspace subscription tier
Source: https://docs.akua.dev/api-reference/workspaces/change-workspace-subscription-tier
/openapi-public.json post /workspaces/{id}/subscription:changeTier
Schedules a subscription tier change for the workspace.
# Create workspace
Source: https://docs.akua.dev/api-reference/workspaces/create-workspace
/openapi-public.json post /workspaces
Creates a workspace for the authenticated user.
# Delete workspace
Source: https://docs.akua.dev/api-reference/workspaces/delete-workspace
/openapi-public.json delete /workspaces/{id}
Asynchronously deletes a workspace and all of its workspace-owned resources.
# Get subscription change request
Source: https://docs.akua.dev/api-reference/workspaces/get-subscription-change-request
/openapi-public.json get /workspaces/{id}/subscription/change_requests/{req_id}
Returns one subscription change request record.
# Get workspace
Source: https://docs.akua.dev/api-reference/workspaces/get-workspace
/openapi-public.json get /workspaces/{id}
Returns the details of a workspace.
# Get workspace access state
Source: https://docs.akua.dev/api-reference/workspaces/get-workspace-access-state
/openapi-public.json get /workspaces/{id}/access_state
Returns whether the workspace is currently accessible and why.
# Get workspace subscription
Source: https://docs.akua.dev/api-reference/workspaces/get-workspace-subscription
/openapi-public.json get /workspaces/{id}/subscription
Returns billing subscription information for a workspace.
# List subscription change requests
Source: https://docs.akua.dev/api-reference/workspaces/list-subscription-change-requests
/openapi-public.json get /workspaces/{id}/subscription/change_requests
Returns subscription tier change requests for workspace.
# List workspace members
Source: https://docs.akua.dev/api-reference/workspaces/list-workspace-members
/openapi-public.json get /workspaces/{id}/members
Returns the members and roles for a workspace.
# List workspaces
Source: https://docs.akua.dev/api-reference/workspaces/list-workspaces
/openapi-public.json get /workspaces
Returns all workspaces visible to the authenticated user.
# Reactivate workspace subscription
Source: https://docs.akua.dev/api-reference/workspaces/reactivate-workspace-subscription
/openapi-public.json post /workspaces/{id}/subscription:reactivate
Reactivates a workspace subscription and clears cancellation schedule.
# Remove workspace member
Source: https://docs.akua.dev/api-reference/workspaces/remove-workspace-member
/openapi-public.json delete /workspaces/{id}/members/{userId}
Removes a user from a workspace.
# Update workspace
Source: https://docs.akua.dev/api-reference/workspaces/update-workspace
/openapi-public.json patch /workspaces/{id}
Updates workspace metadata for the selected workspace.
# Update workspace member role
Source: https://docs.akua.dev/api-reference/workspaces/update-workspace-member-role
/openapi-public.json patch /workspaces/{id}/members/{userId}
Updates the role of a workspace member.
# Authentication
Source: https://docs.akua.dev/apis/authentication
Authenticate with the Akua API using session tokens, workspace API tokens, or JWTs
Every API request requires an `Authorization: Bearer` header with a valid token.
| Method | Format | Best for |
| ------------------- | --------------------- | ------------------- |
| Session token | 32-char random string | CLI (default) |
| Workspace API token | `sk_akua_...` | CI/CD, scripts |
| OAuth2 JWT | `eyJ...` (JWT) | Custom integrations |
For interactive CLI use, **session tokens** are the default (obtained via `cnap auth login`).
For CI/CD and scripts, **workspace API tokens** are recommended.
## CLI authentication
The fastest way to get started is with the CLI:
```bash theme={null}
cnap auth login
```
This opens your browser where you approve the request, then the CLI stores a session token. No manual token management needed.
The CLI uses the [OAuth 2.0 Device Authorization Grant](https://datatracker.ietf.org/doc/html/rfc8628) to authenticate securely without handling your credentials directly.
```mermaid theme={null}
sequenceDiagram
participant CLI
participant Browser
participant Akua
CLI->>Akua: Request device code
Akua-->>CLI: Device code + user code
CLI->>Browser: Open verification URL
Note over CLI: "Enter code: ABCD-EFGH"
Browser->>Akua: User approves
CLI->>Akua: Poll for token
Akua-->>CLI: Session token
Note over CLI: Stored in ~/.cnap/config.yaml
```
The CLI stores your token in `~/.cnap/config.yaml`. Run `cnap auth status` to check your current session.
## Session tokens
When you run `cnap auth login`, the CLI stores a session token. Sessions are long-lived (1 year) and auto-refresh on every use, so active sessions effectively never expire.
If your session ever expires, log in again:
```bash theme={null}
cnap auth login
```
Check your session status:
```bash theme={null}
cnap auth status
```
Session tokens are ideal for interactive CLI use. For non-interactive environments (CI/CD, scripts), use workspace API tokens instead.
## Workspace API tokens
Workspace API tokens are long-lived tokens prefixed with `sk_akua_`. They're the recommended approach for CI/CD pipelines, scripts, and automated workflows.
A token belongs to a **workspace**, not a user. The workspace it's created in is the workspace it acts on — calls made with a workspace API token operate on that workspace implicitly, with no extra header required (see [Workspace scoping](#workspace-scoping)). Creating and revoking tokens is gated by the workspace **owner** or **admin** role.
### Create a token via the CLI
```bash theme={null}
cnap auth login --token sk_akua_...
```
This stores the given token directly in `~/.cnap/config.yaml`.
### Create a token via the dashboard
Create workspace API tokens from the Akua dashboard under **Workspace settings > API tokens** (owner or admin only).
### Create a token via the API
If you already have a valid token, you can create additional workspace API tokens programmatically:
```bash theme={null}
curl -X POST https://api.akua.dev/v1/api_tokens \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "CI pipeline", "expires_at": 1742169600}'
```
Response:
```json theme={null}
{
"id": "j572abc123def456",
"name": "CI pipeline",
"token": "sk_akua_abc123...",
"expires_at": 1734567890000
}
```
The `token` field is only returned once at creation time. Store it securely — it cannot be retrieved later.
### List and revoke tokens
```bash theme={null}
# List the workspace's tokens
cnap auth tokens list
# Revoke a token
cnap auth tokens revoke
```
```bash theme={null}
# List the workspace's tokens
curl https://api.akua.dev/v1/api_tokens \
-H "Authorization: Bearer $AKUA_API_TOKEN"
# Revoke a token
curl -X DELETE https://api.akua.dev/v1/api_tokens/ \
-H "Authorization: Bearer $AKUA_API_TOKEN"
```
## Workspace scoping
Many endpoints operate within a workspace context. How the workspace is selected depends on the credential:
* **Workspace API token** — the token already belongs to a workspace, so that workspace is used automatically. No extra header is needed:
```bash theme={null}
curl https://api.akua.dev/v1/installs \
-H "Authorization: Bearer $AKUA_API_TOKEN"
```
* **Broad credential** (dashboard session or a multi-workspace token) — select the target workspace with the optional `Akua-Context` header:
```bash theme={null}
curl https://api.akua.dev/v1/installs \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Akua-Context: ws_xxx"
```
If a broad credential calls a workspace-scoped endpoint without `Akua-Context`, the request returns `403 Forbidden` — the workspace is required and the request is ambiguous. If you send an `Akua-Context` that names a different workspace than the token already belongs to, you'll also receive a `403 Forbidden`. A matching `Akua-Context` is accepted but redundant.
The CLI stores your active workspace in `~/.cnap/config.yaml` and sets `Akua-Context` automatically when needed. Switch workspaces with `cnap workspaces switch`.
## Security
* Akua **never stores plaintext tokens**. Tokens are hashed before storage.
* Tokens can have an **expiration date**. Expired tokens are rejected automatically.
* Each token tracks its **last used** timestamp for auditing.
* Revoked tokens are deleted immediately and cannot be recovered.
* Session tokens are validated server-side on every request and can be revoked via `cnap auth logout`.
## Related topics
Base URL, conventions, pagination, and error codes.
Manage workspace API tokens programmatically via the API reference.
The Akua CLI and its auth commands.
Download the spec and generate type-safe clients.
# Domain routing API
Source: https://docs.akua.dev/apis/domain-routing
Manage workspace subdomains, preview hostnames, and custom domains through the public API
The domain routing API lets you manage the public hostnames that route traffic to your applications. Use it when you want automation to create preview URLs, attach customer-owned domains, or rename the workspace subdomain that appears in generated hostnames.
Domain routing is independent of how an application was installed. Installations can publish one or more preview hostnames, workspaces own their default subdomain, and custom domains belong to the workspace that controls the DNS relationship.
## Resource model
| Resource | Scope | Use it for |
| ------------------- | ------------ | ------------------------------------------------------------------ |
| Workspace subdomain | Workspace | The default workspace slug used in managed preview hostnames. |
| Preview hostname | Installation | A managed hostname for one application endpoint. |
| Custom domain | Workspace | A domain you own and attach to a workspace for production traffic. |
Workspace-scoped requests resolve the workspace from your credential the same way as the rest of the API — implied by a workspace API token, or selected with the optional `Akua-Context` header for broad credentials. Mutation endpoints are safe to retry with `Idempotency-Key`.
## Workspace subdomains
Every workspace has one subdomain resource. Read it before showing a rename form, and pass the returned `etag` when you submit a rename. If another client changed the subdomain first, the API returns a conflict so your UI can reload the current value.
Get and rename the workspace subdomain.
## Preview hostnames
Preview hostnames expose one installation endpoint through an Akua-managed hostname. Use pinned hostnames when you need a stable name for a known environment. Use floating hostnames when automation needs a fresh preview name without coordinating a specific slug.
List, bind, and delete preview hostnames for an installation.
## Custom domains
Custom domains attach a domain you control to a workspace. The API returns the DNS verification state so you can guide customers through domain control validation before serving production traffic.
Routing mode controls where traffic goes after the domain is active:
* `through_dispatcher` routes through Akua-managed edge dispatching.
* `bypass_dispatcher` is for enterprise traffic paths that use a dedicated target instead of the shared dispatcher.
Create, verify, update, and delete custom domains.
## Long-running changes
Domain mutations return an operation. Store the operation ID and call the operation `:wait` endpoint when you need synchronous handoff behavior.
For dashboards and CLIs, prefer showing the operation timeline instead of repeatedly fetching the domain resource. The operation response tells you when the routing change has been accepted and when background validation finishes.
## Related topics
Authentication, pagination, idempotency, and error handling.
How managed preview hostnames route to your applications.
Set up API tokens for programmatic access.
Track long-running infrastructure changes.
# Introduction
Source: https://docs.akua.dev/apis/introduction
Programmatic access to Akua resources for automation, CLI tools, and integrations
The Akua API is a RESTful API that lets you manage workspaces, clusters, products, installations, and repositories programmatically. It powers the [Akua CLI](/cli) and can be used to build custom integrations.
## Base URL
All API requests are made to:
```
https://api.akua.dev/v1
```
An illustrative request:
```bash theme={null}
curl https://api.akua.dev/v1/workspaces \
-H "Authorization: Bearer $AKUA_API_TOKEN"
```
Workspace-scoped endpoints resolve the workspace from your credential. A workspace API token already belongs to a workspace, so you can omit any workspace header entirely. With a broad credential (dashboard session or multi-workspace token), select the workspace with the optional `Akua-Context` header:
```bash theme={null}
curl https://api.akua.dev/v1/installs \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Akua-Context: ws_xxx"
```
Learn how to create tokens, authenticate with the CLI, and use JWTs.
## Conventions
The API uses `snake_case` for all field names. This keeps responses consistent regardless of the client language and matches the format you see in curl, logs, and debugging tools.
## Response format
**Single objects** are returned directly (no wrapper):
```json theme={null}
{
"id": "j572abc123def456",
"name": "my-workspace",
"created_at": 1734567890000
}
```
**List responses** return `data` with flat pagination fields:
```json theme={null}
{
"data": [
{ "id": "j572abc123def456", "name": "my-workspace", "created_at": 1734567890000 }
],
"has_more": true,
"next_cursor": "opaque..."
}
```
**Error responses** use an `error` envelope:
```json theme={null}
{
"error": {
"code": "not_found",
"message": "Install not found"
}
}
```
## Pagination
List endpoints support cursor-based pagination with two query parameters:
| Parameter | Type | Default | Description |
| --------- | ------- | ------- | ----------------------------------------------- |
| `limit` | integer | 50 | Items per page (1–100) |
| `cursor` | string | (none) | Value of `next_cursor` from a previous response |
## Error codes
| HTTP status | Code | Description |
| ----------- | ------------------ | ------------------------------ |
| 400 | `bad_request` | Malformed request |
| 401 | `unauthorized` | Missing or invalid token |
| 403 | `forbidden` | Not a member of the workspace |
| 404 | `not_found` | Resource does not exist |
| 409 | `conflict` | Resource already exists |
| 422 | `validation_error` | Request body failed validation |
| 500 | `internal_error` | Unexpected server error |
## Interactive reference
The API spec is also available as an interactive reference:
Interactive API explorer with request builder.
Raw OpenAPI 3.1 specification (JSON).
## Related topics
Create tokens and learn about supported auth methods.
Download the spec and generate type-safe clients.
Install the Akua CLI for terminal-based workflows.
Connect AI tools to Akua docs and infrastructure.
# OpenAPI specification
Source: https://docs.akua.dev/apis/openapi
Download the spec, generate type-safe clients, and stay in sync with API changes
Akua publishes an [OpenAPI 3.1](https://spec.openapis.org/oas/v3.1.0) specification that describes every endpoint, parameter, and response shape in this documentation. Use it to generate type-safe clients in any language, validate requests in your tests, and keep your integrations in lockstep with the API.
## Where to get the spec
The spec is available in two forms:
| Source | URL | Use case |
| --------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| Live API | `https://api.akua.dev/v1/openapi.json` | Always reflects the deployed API. Cache this for production codegen pipelines. |
| Static snapshot | [`docs/openapi-public.json`](https://github.com/akua-dev/cnap/blob/main/docs/openapi-public.json) | Versioned alongside the docs. Use for CI builds that need a stable input. |
The two are kept in sync by Akua's CI: every pull request that changes a public route must update `docs/openapi-public.json` or the build fails.
## Generate a client
Most languages have mature OpenAPI codegen tooling. Pick whichever fits your stack:
### TypeScript and JavaScript
[`openapi-typescript`](https://github.com/openapi-ts/openapi-typescript) generates a single `.d.ts` file with no runtime dependencies. Pair it with [`openapi-fetch`](https://github.com/openapi-ts/openapi-typescript) for a type-safe `fetch` wrapper.
```bash theme={null}
# Generate types
npx openapi-typescript https://api.akua.dev/v1/openapi.json -o src/akua-api.d.ts
```
```ts theme={null}
import createClient from 'openapi-fetch';
import type { paths } from './akua-api';
const client = createClient({
baseUrl: 'https://api.akua.dev/v1',
headers: {
Authorization: `Bearer ${process.env.AKUA_API_TOKEN}`,
// Optional — omit when using a workspace API token (workspace is implied).
// Set only for broad credentials to select the target workspace.
'Akua-Context': process.env.AKUA_WORKSPACE_ID
}
});
const { data, error } = await client.GET('/installs/{id}', {
params: { path: { id: 'j572abc123' } }
});
```
### Go
The Akua CLI uses [`oapi-codegen`](https://github.com/oapi-codegen/oapi-codegen) to generate a strongly-typed Go client.
```bash theme={null}
# Generate a client package
go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen \
-package akua \
-generate types,client \
-o akua/client.gen.go \
https://api.akua.dev/v1/openapi.json
```
### Python
[`openapi-python-client`](https://github.com/openapi-generators/openapi-python-client) emits a Pydantic-typed package.
```bash theme={null}
pip install openapi-python-client
openapi-python-client generate --url https://api.akua.dev/v1/openapi.json
```
### Other languages
The [OpenAPI Generator](https://openapi-generator.tech/docs/generators) project ships generators for 50+ languages, including Java, C#, Rust, PHP, and Ruby. The Akua spec is plain OpenAPI 3.1 with no vendor extensions, so any compliant generator works.
## Versioning
The API path includes a version segment (`/v1/...`). Breaking changes ship under a new version path; the previous version stays available for at least 12 months after a new one launches.
Inside a version, Akua follows additive evolution:
* New endpoints and new optional fields can appear at any time.
* Existing fields are never removed or renamed within a version.
* Validation rules can tighten (rare; flagged in the [changelog](/changelog)).
If your generated client compiled against an older spec snapshot, regenerating against a newer snapshot is always safe within the same major version.
## Stay in sync
For CI pipelines that consume the spec, pin to the static snapshot file in this repository and bump it deliberately:
```bash theme={null}
# Fail the build if the local copy drifts from upstream
curl -fsS https://raw.githubusercontent.com/akua-dev/cnap/main/docs/openapi-public.json -o /tmp/upstream.json
diff -q /tmp/upstream.json ./vendor/akua-openapi.json
```
For long-running services, prefer the live URL with a short cache so new endpoints become available the moment they ship.
## Related topics
API base URL, conventions, and error envelope.
Workspace API tokens and JWT auth.
The Akua CLI built on top of the same API.
# Enterprise
Source: https://docs.akua.dev/billing/enterprise
Custom limits, dedicated support, and compliance for organizations with larger requirements
Enterprise is not a fixed plan. It is a custom arrangement for organizations that need more than Pro provides. There is no self-serve Enterprise tier in the dashboard.
Talk to us about your requirements, pricing, and migration plan.
See the full enterprise pitch with video walkthrough.
## What Enterprise provides
### Custom resource limits
Pro has fixed limits (3 machines, 8 CPU cores, 16 GiB). Enterprise workspaces get custom limits set per-workspace: 50 machines, 200 CPU cores, 1 TiB of memory, or whatever the workload requires. Contact us to discuss your numbers.
### Dedicated support
* Direct access to the engineering team.
* Custom onboarding and migration assistance.
* Priority issue resolution.
* Architecture review for your deployment.
### Compliance and security
Enterprise customers often require:
* **Data residency**: workloads stay in specific regions (EU, US, or custom).
* **ISO 27001** and **SOC 2** certification (planned).
* **GDPR** compliance documentation.
* **Dedicated infrastructure**: isolated control planes with no shared resources.
* **Security reviews**: we participate in your vendor assessment process.
### Flexible billing
* Annual contracts with volume discounts.
* Usage-based billing for compute beyond the included allocation.
* Consolidated invoicing across multiple workspaces.
* Custom payment terms.
## How Enterprise differs from Pro
| | Pro | Enterprise |
| ------------------ | ------------------------- | -------------------------------- |
| **Price** | €20/month fixed | Custom (annual contract) |
| **Limits** | 3 machines, 8 CPU, 16 GiB | Custom per workspace |
| **Instance types** | All provider types | All, plus reserved capacity |
| **Support** | Standard | Dedicated engineering contact |
| **Compliance** | Shared infrastructure | Dedicated option, certifications |
| **Billing** | Monthly self-serve | Annual, usage-based, invoiced |
| **Onboarding** | Self-serve docs | Hands-on migration support |
## Bring your own key with Enterprise
Most enterprise customers use BYOM (bring your own machine) alongside their custom limits. This combination provides:
* **No Akua compute costs**: you pay your provider directly at their published prices.
* **No compute quotas**: BYOM bypasses machine, CPU, and memory limits regardless of plan.
* **Full provider choice**: any instance type, any region, any account.
* **Akua manages Kubernetes**: cluster lifecycle, auto-scaling, monitoring, and suspend/resume.
* **Enterprise support**: dedicated engineering contact for the management layer.
* **Transparent costs**: your cloud bill is between you and your provider, visible in their console.
**Zero infrastructure markup.** You bring your own cloud account (Hetzner or any supported provider). You pay that provider at their published prices. Akua charges only for the management subscription, never a percentage on top of infrastructure costs.
## Getting started
Enterprise arrangements are handled directly. Contact us to discuss:
* Your workload requirements (machines, CPU, memory, regions).
* Compliance needs (certifications, data residency).
* Billing preferences (annual, usage-based, invoiced).
* Migration timeline (existing infrastructure to Akua).
30-minute call to discuss your requirements, pricing, and migration timeline.
## Related topics
Understand subscription management and lifecycle states.
Full plan comparison — Free, Pro, and Enterprise.
Connect your own cloud machines to bypass compute limits.
Manage teams and customer workspaces at scale.
# Billing
Source: https://docs.akua.dev/billing/overview
Manage your workspace subscription and understand how billing works
Your Akua subscription is tied to your workspace, not your personal account. Each workspace can have its own plan.
**Two different billing integrations — don't confuse them.**
* **This page**: Your subscription to Akua (Free/Pro/Enterprise). This is what you pay to use the platform.
* **Marketplace payments**: Your customers paying you for your products. This uses Stripe Connect with your own merchant account and is enabled for workspaces as the commerce path rolls out.
These are completely separate. Upgrading your Akua plan does not affect how your marketplace customers are billed, and vice versa.
## Pricing philosophy
Akua does not mark up infrastructure. When you use your own cloud provider key (BYOM), you pay the provider directly at their published prices: Hetzner at Hetzner prices, AWS at AWS prices. Akua charges only for the management layer.
See the [plan comparison →](/pricing#plan-comparison) for the full tier breakdown (Free, Pro, Enterprise).
## Upgrading to Pro
Go to **Billing** in the dashboard sidebar. Click **Upgrade to Pro** to start a checkout session. Your workspace is upgraded immediately after payment.
## Managing your subscription
Pro workspaces can manage their subscription from the **Billing** page. Click **Manage Subscription** to open the billing portal where you can:
* Update your payment method
* View invoices and payment history
* Cancel your subscription
## Cancellation
When you cancel your Pro subscription:
1. Your workspace stays on Pro until the end of the current billing period.
2. You receive a confirmation email with a summary of what changes on the free tier.
3. The dashboard shows a cancellation notice with the exact end date.
4. You can reactivate any time before the period ends from the billing portal.
When the subscription period ends:
1. Your workspace returns to the free tier.
2. Auto-scaling is paused on managed clusters (BYOM clusters are unaffected).
3. Akua-managed machines are [suspended](/clusters/machines#suspend-and-resume) (not deleted).
4. Snapshots are kept for 90 days so you can resume them if you re-subscribe.
After 90 days, suspended machine snapshots are permanently deleted. Re-subscribing after that point starts fresh with no data recovery.
## Re-subscribing
When you upgrade again after cancellation:
1. Auto-scaling is re-enabled on managed clusters.
2. The dashboard shows any suspended machines with a **Resume** button.
3. Resuming a machine restores it from its snapshot: same hostname, same data.
## Bring your own cloud key
Adding your own cloud provider API key (BYOM) bypasses all machine quotas and TTL limits. Your machines run in your cloud account and you pay the provider directly. Akua manages the Kubernetes lifecycle.
BYOM works on any plan, including Free. Configure it from the **Compute** page in the dashboard.
Bring your own cloud key to bypass all machine quotas and TTL limits on any plan. You pay your cloud provider directly; Akua adds zero markup on infrastructure costs.
## Workspace access state
Every workspace has a current access state that determines what operations are permitted. You can read it from the [API](/api-reference/workspaces/get-workspace-access-state) at any time. The possible states are:
| State | Meaning |
| --------------- | ------------------------------------------------------------------------------------- |
| `active` | Normal operation: all resources are available. |
| `payment_grace` | A recent payment failed; existing resources keep running while the issue is resolved. |
| `restricted` | New provisions and installs are blocked; critical existing resources continue. |
| `suspended` | Resources are suspended; re-subscribing restores them. |
| `ended` | Subscription has ended and retention period has passed. |
| `reactivating` | A successful payment was processed and resources are being restored. |
## API
Manage subscriptions and check access state programmatically.
Subscription, access state, billing portal, and tier change endpoints.
Mint API tokens for programmatic access.
## Related topics
Compare plans and resource limits in detail.
Machine lifecycle, suspend, and resume.
Understand resource limits and check usage.
Create private customer purchase links and prepare commercial distribution.
# Plan tiers
Source: https://docs.akua.dev/billing/tiers
How your plan tier is resolved and how it affects quotas, instance types, and machine lifecycle
Your plan tier determines your resource limits, available instance types, and machine lifecycle rules. Akua resolves your effective tier through a specific chain, and understanding this helps you predict what happens when you upgrade, downgrade, or work across multiple workspaces.
## Tier resolution
### Workspace tier
Each workspace has its own plan:
* **No active subscription** → Free tier
* **Pro plan active** → Pro tier (set automatically when you subscribe)
The workspace tier controls quota limits, instance type filtering, and machine TTL.
### User tier
Some operations use a user-level tier such as rate limit naming and quota info display. Your user tier is the **highest tier across all your workspaces**:
* You belong to 3 workspaces: 2 Free + 1 Pro → your user tier is **Pro**
* You belong to 2 workspaces: both Free → your user tier is **Free**
Upgrading one workspace to Pro also elevates your personal rate limits.
## What each tier controls
### Instance type filtering
When your cluster scales, the available instance types depend on the workspace tier:
| Tier | Available instance types |
| --------------- | ------------------------------- |
| Free | Small, affordable types only |
| Pro | All types from the provider |
| BYOM (any tier) | All types in your cloud account |
### Quota enforcement
Quotas are enforced at the moment a machine record is created, preventing concurrent requests from exceeding the limit.
| Metric | Free limit | Pro limit | BYOM |
| --------- | ---------- | --------- | --------- |
| Machines | 1 | 3 | Unlimited |
| CPU cores | 2 | 8 | Unlimited |
| Memory | 4 GiB | 16 GiB | Unlimited |
| Clusters | 1 | 3 | N/A |
Free-tier workspaces are also subject to a per-user check to prevent circumventing limits by creating multiple free workspaces. Pro workspaces skip this check.
### Machine TTL
| Tier | TTL | What happens |
| ------------------- | -------- | ---------------------------------------------------- |
| Free (Akua-managed) | 7 days | Auto-deleted with email reminders at 5d, 2d, and 24h |
| Pro (Akua-managed) | No limit | Runs until manually deleted or suspended |
| BYOM (any tier) | No limit | You pay the provider directly |
### Auto-scaling behavior
| Tier | Auto-scaling |
| -------------------- | ------------------------------------------- |
| Free | Enabled within quota (1 machine max) |
| Pro | Enabled within quota (3 machines max) |
| Downgraded (was Pro) | Paused automatically when subscription ends |
## When tiers change
### Upgrade (Free to Pro)
Takes effect immediately:
1. All provider instance types become available (not just small types).
2. Quotas increase (1 → 3 machines, 2 → 8 CPU cores, and so on).
3. Machine TTL is removed; existing machines no longer expire.
4. Auto-scaling limits expand.
### Downgrade (Pro to Free)
Takes effect at the end of the billing period:
1. Akua-managed machines are [suspended](/clusters/machines#suspend-and-resume) (not deleted).
2. Auto-scaling is paused on managed clusters.
3. Quotas revert to free limits.
4. Instance type filtering returns to small types only.
5. BYOM machines are unaffected.
### BYOM (any tier)
Adding your own cloud API key bypasses all quota enforcement:
* No machine count limit.
* No CPU or memory limit.
* No TTL.
* All instance types available in your cloud account.
* No auto-scaling restrictions.
The only Akua charge is the management subscription. Cloud compute costs go directly to your provider.
## Related topics
Upgrade, manage, and cancel your subscription.
Full plan comparison with included limits.
How resource quotas are enforced across workspaces.
Connect your own cloud machines to bypass compute limits.
# Platform capabilities
Source: https://docs.akua.dev/capabilities
How the Akua product catalog maps to the docs
Akua's public [product catalog](https://akua.dev/platform/products) shows platform capabilities by category: Compute, Packaging, Delivery, Networking, Commerce, Agents, and Platform. The docs use a task-oriented sidebar, so the category names do not always appear as top-level navigation items.
Use this page as the bridge between the catalog and the docs.
## Capability map
Create managed clusters, import existing clusters, add workers, choose regions, and manage compute lifecycle.
Define reusable Package versions, input schemas, source composition, and package authoring.
Install, render, customize, version, and update applications in customer or internal workspaces.
Expose applications with preview domains, direct IP routing, custom domains, and Gateway API routes.
Sell software through Offers, checkout-ready order drafts, and customer distribution paths.
Use hosted agents, connect external assistants, and give agents current Akua documentation.
Manage workspaces, organizations, dashboards, API tokens, notifications, private registries, billing, security, and quotas.
## Products vs platform capabilities
Akua uses the word **Product** in two different user contexts:
* **Platform capabilities** are the things Akua itself provides, such as Compute, Delivery, Commerce, and Agents.
* **Sellable products** are the software packages you create and sell to customers through the marketplace or private Offers.
If you want to understand the platform surface, start with the capability map above. If you want to package and sell your own software, start with [Sellable products](/products).
## What to read first
| Catalog category | Common catalog rows | Start with |
| ---------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Compute** | KaaS, BYOM, imported clusters, workers, regions, hibernation | [Compute](/compute), [Clusters](/clusters), [Add workers](/clusters/add-workers) |
| **Packaging** | Akua Packages, Helm sources, Kustomize sources, Package versions, private registries, generated forms | [Packages](/packages), [Package format](/akua/package-format), [Private registries](/platform/private-registries) |
| **Delivery** | Atomic install, installation repositories, lifecycle, versioning, generated manifests, repository change requests | [Delivery](/delivery), [Installations](/installs), [Installation repositories](/installs/repositories), [Package versioning](/installs/versioning) |
| **Networking** | Preview domains, custom domains, direct IP routing, Gateway API, Cloudflare tunnels | [Networking](/networking), [Preview domains](/networking/preview-domains), [Direct IP routing](/networking/direct-ip), [Cloudflare Tunnel](/networking/cloudflare-tunnel) |
| **Commerce** | Products, Offers, generated configure UI, order drafts, checkout, payments | [Commerce](/commerce), [Sellable products](/products), [Offers](/marketplace/offers), [Order drafts](/marketplace/order-drafts) |
| **Agents** | Sessions, turns, events, approval gates, ambient agents, Code Mode | [Agents](/agents), [Documentation MCP](/ai/docs-mcp), [Platform MCP](/ai/platform-mcp) |
| **Platform** | Workspaces, organizations, API tokens, secrets, quotas, dashboards | [Platform](/platform), [Workspaces](/workspaces), [Organizations](/platform/organizations), [Security](/platform/security), [Quotas](/platform/quotas) |
# Changelog
Source: https://docs.akua.dev/changelog
Product updates and announcements
## Per-installation git repositories
Every installation now gets its own private git repository. Clone it, edit the inputs or composition, send the change through review, and Akua rolls it out. The repository is the same source of truth the dashboard reads from. UI edits and accepted repository changes converge on the same state.
Use the new repository to:
* Patch any field on any rendered resource without forking the upstream package.
* Add resources the upstream doesn't include (extra ConfigMaps, sidecars, network policies).
* Roll back to a previous deployment with `git revert`.
* Pin to a specific upstream version and update on your schedule.
Read the new [Customize an installation via git](/installs/install-repo) guide.
## Repositories REST API
New `/v1/repositories` endpoints let you list and inspect installation repositories programmatically. Each entry includes the clone URL, the latest deployed commit, and a content hash that lets you skip redundant deploys when nothing changed. See the [Repositories API reference](/api-reference/repositories/list-repositories-in-workspace).
## Read-only access tokens
Tokens minted for read-only consumers (deployment systems, CI artifacts) are now physically scoped to fetch operations on the platform side. A leaked read token cannot be used to push, regardless of how it gets misused.
## Packages API
New `/v1/packages` endpoints expose the Package definitions backing your products, including the typed input schema served at `/v1/packages/{id}/versions/{semver}/inputs`. Use them to drive your own install flows, generate type-safe client SDKs, or audit which Package version every product points at. See the [Packages API reference](/api-reference/packages/list-packages).
## AI and Agents: Platform MCP with Code Mode
AI integrations can now manage Akua infrastructure through the Model Context Protocol. The platform MCP server uses Code Mode: instead of one tool per API endpoint, agents get two tools (`search` + `execute`) and write JavaScript to compose API calls in a sandboxed V8 isolate. Inspired by [CodeAct](https://machinelearning.apple.com/research/codeact) research and powered by the open-source [`akua-dev/codemode`](https://github.com/akua-dev/codemode) library.
## Public REST API
Full RESTful API at `api.akua.dev/v1` for managing workspaces, clusters, packages, products, installations, and repositories programmatically. Supports workspace-owned API tokens and JWT authentication. A workspace API token implies its workspace, so most calls need no workspace header; broad credentials select the workspace with the optional `Akua-Context` header. Powers both the CLI and the platform MCP server.
## Cloudflare Tunnel Preview Domains
Instant `*.akua.run` HTTPS URLs for every app, with no DNS setup or Cloudflare account required. Also supports custom domains using your own Cloudflare credentials, managed per-workspace in Settings.
## Interactive Terminal
Shell into running containers directly from the dashboard. Select a pod and container, and get a fully interactive terminal session powered by xterm.js and WebSocket.
## App Dashboard Overhaul
Redesigned app landing page with new branding, overhauled create flow, and dedicated install detail routes for better navigation.
## Passwordless Authentication
New passwordless magic-link login experience.
## Gateway API & HTTPRoutes
Full Gateway API support with HTTPRoute-based ingress. Configure routing rules for your applications without touching raw Kubernetes manifests.
## Package generation
Akua now renders per-installation manifests from your Package and the customer's inputs automatically, with no manual chart authoring needed.
## Registry Proxy
Pull images through Akua's registry proxy, enabling private registry support without exposing credentials to clusters.
## MCP Server
Added a Model Context Protocol server with ArtifactHub tools for Helm chart discovery and management.
## Installation status
New installation tracking surfaces show deployment progress, generated resources, and live status as installs converge on clusters.
## Real-Time Application Logs
Stream live logs from running pods directly in the dashboard.
## Workspace & Cluster UX Improvements
Revamped workspace selection UI, cluster creation and import flows, and updated terminology from "Projects" to "Workspaces" across the platform.
## Product Settings & Deployment
Enhanced product display with deploy functionality, product preview in the creation flow, and a new product settings step.
## Quickstart Onboarding
New guided quickstart flow to get users from sign-up to first deployment. Includes pricing display and state persistence across navigation.
## Self-Install for Merchants
Merchants can now trigger product installs into their own workspace without payment, enabling self-service testing.
## OIDC Session Refresh
Automatic OIDC session refresh on tab activation, so no more expired sessions when switching back to the dashboard.
## Global Search with Product Sheets
Search now surfaces catalog items with integrated product detail sheets.
## Kubernetes as a Service
Provision and manage Kubernetes clusters directly from Akua. Includes worker node bootstrap, kubeconfig download, and full lifecycle management.
## Stripe Integration
Automatic Stripe customer creation for billing and payment flows.
## Auto Migration
Database migrations now run automatically at startup, with no manual migration steps needed.
## Test Infrastructure
Added comprehensive test suite foundation for the platform.
## Helm MVP
The foundational release: Helm-based products, cluster management, region support, and app installs. The core platform that everything else builds on.
# CLI
Source: https://docs.akua.dev/cli
Manage Akua resources from your terminal
The Akua CLI gives you terminal-based access to all API operations, with interactive pickers, streaming logs, and shell access to running pods.
## Quick start
```bash theme={null}
brew install akua-dev/tap/cnap
```
```bash theme={null}
go install github.com/cnap-tech/cli/cmd/cnap@latest
```
Go installs use the CLI's declared module path, which remains
`github.com/cnap-tech/cli`.
```bash theme={null}
git clone https://github.com/akua-dev/cli.git
cd cli
go build -o cnap ./cmd/cnap
```
```bash theme={null}
cnap auth login
```
This opens your browser for approval, then stores a session token in `~/.cnap/config.yaml`.
For CI/CD, use `cnap auth login --token sk_akua_...` with a workspace API token. You can also set the `AKUA_API_TOKEN` environment variable.
```bash theme={null}
cnap clusters list
```
## Authentication
```bash theme={null}
# Log in via browser (device flow); stores a session token
cnap auth login
# Log in with a workspace API token (for CI/CD)
cnap auth login --token sk_akua_...
# Check authentication status (shows token type and expiry)
cnap auth status
# Remove stored credentials (revokes session server-side)
cnap auth logout
```
Sessions are long-lived and auto-refresh on use.
## Output formats
```bash theme={null}
# Table output (default)
cnap installs list
# JSON output
cnap installs list -o json
# Quiet mode (IDs only)
cnap installs list -o quiet
# Set default format in config
cnap config set output.format json
```
The `-o` / `--output` flag is available on all commands.
## Pagination
List commands accept `--limit` and `--cursor` flags for pagination:
```bash theme={null}
# First page (10 items)
cnap clusters list --limit 10
# Next page using cursor from previous response
cnap clusters list --limit 10 --cursor
```
Default limit is 50, maximum is 100.
## Configuration
The CLI stores configuration in `~/.cnap/config.yaml`:
```yaml theme={null}
api_url: https://api.akua.dev
auth_url: https://akua.dev
active_workspace: j575xyz789ghi012
auth:
token: a1b2c3d4e5f6... # session token from device flow (or sk_akua_... for workspace API tokens)
output:
format: table
```
### Environment variables
| Variable | Description | Overrides |
| ---------------- | -------------------------------------------- | ---------------------- |
| `AKUA_API_TOKEN` | API token (workspace token or session token) | `auth.token` in config |
| `AKUA_API_URL` | API base URL | `api_url` in config |
| `AKUA_AUTH_URL` | Auth/dashboard URL | `auth_url` in config |
| `AKUA_DEBUG` | Enable debug logging | (none) |
## Debugging
Enable verbose output with the `--debug` flag or `AKUA_DEBUG=1`:
```bash theme={null}
cnap --debug installs list
```
This shows HTTP request and response details for troubleshooting.
## Resource commands
Switch active workspace and list all workspaces.
List, update, delete clusters, and download kubeconfigs.
List, inspect, and delete products.
Deploy products, stream logs, and open an interactive shell.
Manage cluster context and placement.
Manage container registry credentials.
## Related topics
REST API conventions, pagination, and error codes.
Mint API tokens for programmatic access.
Connect AI tools to the Akua documentation corpus.
Organize products and clusters into workspaces.
# Clusters
Source: https://docs.akua.dev/cli/clusters
List, inspect, update, delete clusters, and download kubeconfigs from the terminal
Manage your Akua clusters from the command line. The clusters commands let you inspect cluster state, update configuration, download kubeconfigs, and delete clusters you no longer need.
**Alias:** `cnap cl`
## List clusters
```bash theme={null}
cnap clusters list
```
## Get cluster details
```bash theme={null}
cnap clusters get
```
## Update a cluster
```bash theme={null}
cnap clusters update --name "staging"
cnap clusters update --region
```
| Flag | Description |
| ---------- | ---------------- |
| `--name` | New cluster name |
| `--region` | New region ID |
## Delete a cluster
```bash theme={null}
cnap clusters delete --force
```
The `--force` flag is required to confirm deletion.
## Download kubeconfig
```bash theme={null}
# Print to stdout
cnap clusters kubeconfig
# Write to file (mode 0600)
cnap clusters kubeconfig -o kubeconfig.yaml
```
Downloads the admin kubeconfig for a managed cluster. The cluster must be in `RUNNING` status.
Pipe directly into kubectl: `cnap clusters kubeconfig | kubectl --kubeconfig /dev/stdin get nodes`
## API reference
Endpoints, parameters, response shapes, and try-it playground.
Mint API tokens for programmatic access.
## Related topics
Understand managed and imported cluster types.
Deploy products and stream logs from the CLI.
Understand how clusters, workers, and placement fit together.
Authentication, output formats, and configuration.
# Installs
Source: https://docs.akua.dev/cli/installs
Deploy products, stream logs, and open an interactive shell from the terminal
The installs commands let you create product installs, manage installations, stream pod logs, and open an interactive shell into a running container.
**Alias:** `cnap inst`
## List installs
```bash theme={null}
cnap installs list
```
## Get install details
```bash theme={null}
cnap installs get
```
## Create an install
```bash theme={null}
cnap installs create --product --region
```
Installs a product into a region. The platform processes the installation in the background.
| Flag | Required | Description |
| ----------- | -------- | ----------- |
| `--product` | Yes | Product ID |
| `--region` | Yes | Region ID |
## Delete an install
```bash theme={null}
cnap installs delete --force
```
Removes the install and its associated resources. The `--force` flag is required to confirm deletion.
## List pods
```bash theme={null}
cnap installs pods
```
## Stream logs
```bash theme={null}
# Interactive picker
cnap installs logs
# With explicit arguments
cnap installs logs --pod --container --follow
```
When run without arguments, shows cascading pickers to select an install, pod, and container.
| Flag | Description |
| -------------- | ------------------------------------- |
| `--pod` | Pod name (all pods if omitted) |
| `--container` | Container name |
| `-f, --follow` | Follow log output (default: true) |
| `--tail` | Number of lines to tail |
| `--since` | Only return logs newer than N seconds |
## Interactive shell
```bash theme={null}
# Interactive picker
cnap installs exec
# With explicit arguments
cnap installs exec --pod --container --shell /bin/bash
```
Opens an interactive shell session inside a pod container.
| Flag | Description |
| ------------- | --------------------------------- |
| `--pod` | Pod name |
| `--container` | Container name |
| `--shell` | Shell to use (default: `/bin/sh`) |
## API reference
Endpoints, parameters, response shapes, and try-it playground.
Mint API tokens for programmatic access.
## Related topics
List and inspect the products you can install.
Manage the clusters your installs run on.
Manage the cluster context where installs run.
Authentication, output formats, and configuration.
# Products
Source: https://docs.akua.dev/cli/products
List, inspect, and delete products from the terminal
The products commands let you browse and manage the products in your workspace. Use these commands to inspect product details or remove products you no longer need.
**Alias:** `cnap prod`
## List products
```bash theme={null}
cnap products list
```
## Get product details
```bash theme={null}
cnap products get
```
## Delete a product
```bash theme={null}
cnap products delete --force
```
The `--force` flag is required to confirm deletion. If the product has active installs, delete those first.
## API reference
Endpoints, parameters, response shapes, and try-it playground.
Mint API tokens for programmatic access.
## Related topics
Deploy a product and manage its installs.
Manage the cluster context where products can be installed.
Switch the active workspace to see its products.
Authentication, output formats, and configuration.
# Registry
Source: https://docs.akua.dev/cli/registry
Manage container registry credentials from the terminal
Registry credentials allow Akua to pull container images from private registries when deploying your products. Use the registry commands to list and remove credentials stored in your workspace.
**Alias:** `cnap reg`
## List credentials
```bash theme={null}
cnap registry list
```
## Delete a credential
```bash theme={null}
cnap registry delete --force
```
The `--force` flag is required to confirm deletion.
## API reference
Endpoints, parameters, response shapes, and try-it playground.
Mint API tokens for programmatic access.
## Related topics
Manage the products that use registry credentials.
Switch the active workspace to see its credentials.
Deploy products that pull from private registries.
Authentication, output formats, and configuration.
# Workspaces
Source: https://docs.akua.dev/cli/workspaces
Switch active workspace and list all workspaces from the terminal
The workspaces commands let you list your workspaces and switch which one the CLI targets. The active workspace is sent with every API request so all other commands automatically operate in the right context.
**Alias:** `cnap ws`
## List workspaces
```bash theme={null}
cnap workspaces list
```
## Switch workspace
```bash theme={null}
# Interactive picker
cnap workspaces switch
# By ID
cnap workspaces switch
```
If no ID is given, an interactive picker lets you choose from your workspaces. The selection is saved to `~/.cnap/config.yaml` as `active_workspace`.
## API reference
Endpoints, parameters, response shapes, and try-it playground.
Mint API tokens for programmatic access.
## Related topics
Understand workspace roles and member management.
Manage clusters in the active workspace.
Browse products in the active workspace.
Authentication, output formats, and configuration.
# Clusters
Source: https://docs.akua.dev/clusters
Understand how clusters work in Akua for deploying and managing your applications
A cluster is a group of one or more machines that are managed by Kubernetes to deploy your applications and keep them running. Clusters are where you run applications for your team, deploy products to customers, and host your software.
Akua provides **Kubernetes as a Service (KaaS)** where Akua manages the control plane and handles all Kubernetes operations on your worker nodes (joining, configuring, maintaining), while you stay in control of your infrastructure and billing.
## Choosing your cluster type
Akua offers two ways to set up your clusters: managed clusters where Akua handles all Kubernetes operations, or imported clusters where you bring your existing Kubernetes infrastructure. Both approaches let you deploy applications for your team, sell products to customers, and host your software, but managed clusters remove the operational complexity of running Kubernetes yourself.
### Managed clusters
Managed clusters are fully provisioned and maintained by Akua. Akua's **Kubernetes as a Service (KaaS)** provides fully managed infrastructure where Akua manages the control plane and handles all Kubernetes operations on your workers, while you maintain control over your infrastructure choices and billing.
You add your own workers to the cluster, and Akua handles joining, configuring, and maintaining them. This option is ideal for most users who want to focus on building and selling software without the operational overhead of managing Kubernetes.
Managing a Kubernetes control plane requires expertise in multiple complex areas. You need to handle certificate management and rotation to keep your cluster secure, manage etcd cluster operations including backup and recovery to protect your data, configure the API server with proper security settings, tune the controller manager and scheduler for optimal performance, set up network policies and CNI configuration for proper networking, and establish monitoring, logging, and observability to track cluster health.
The control plane also needs dedicated infrastructure including an extra IP address, load balancing, and failover mechanisms to ensure high availability. All of this is infrastructure complexity that stands between you and running your applications.
Akua handles all of this for you, so you can focus on building and selling software instead of managing infrastructure operations.
**Key benefits:**
* **Zero operational overhead** - Akua manages the control plane
* **Automated provisioning** - Get from zero to production-ready cluster in minutes
* **Self-healing infrastructure** - Automatic recovery from component failures
* **24/7 monitoring** - Proactive issue detection and resolution
* **Automatic updates** - Security patches and Kubernetes version upgrades handled for you
* **Security hardening** - Built-in security best practices and regular updates
* **High availability** - Multi-zone control plane for maximum uptime
* **Multi-cloud support** - Use any provider or mix providers
* **Streamlined onboarding** - Developer-friendly experience reduces time-to-market
* **Cost optimization** - Pay only for compute resources you actually use
* **Seamless scaling** - Add or remove workers as your needs change
[Learn how to create a managed cluster →](/clusters/create)
### Imported clusters
Imported clusters allow you to connect your existing Kubernetes infrastructure from any provider (EKS, GKE, AKS, self-managed, or others). This is suitable if you already have an investment in Kubernetes, require specific custom configurations, or prefer to maintain your current cluster management approach.
* **Any Kubernetes cluster** - EKS, GKE, AKS, self-managed, or others
* **Cluster management** - Control plane and worker operations are managed by your cloud provider or yourself, depending on your cluster type
* **Akua handles product installs** - Akua deploys products to your imported cluster, but cluster operations remain outside Akua's management
* **Existing investment** - Leverage current Kubernetes infrastructure
[Learn how to import a cluster →](/clusters/import)
**New to Kubernetes?** Akua's KaaS is designed to be beginner-friendly while remaining powerful enough for enterprise workloads. Akua's managed approach removes the learning curve typically associated with Kubernetes operations.
KaaS integrates with all other Akua features including marketplace deployment, user management, billing, and monitoring. It's designed to provide a complete platform experience rather than just infrastructure.
## How clusters work with products
Akua automatically handles product installs when customers complete purchases. The platform synchronizes your Package resources with the destination cluster based on the customer's selected region. Each product install gets its own dedicated namespace to avoid conflicting resources and provide security and isolation between different customer installs. When installs fail or customers cancel, Akua automatically cleans up all associated resources to keep your infrastructure tidy.
**Resource strategy:** Use shared clusters when you control the software. For customers running custom code (container images, game server plugins), use dedicated machines or clusters. Alternatively, use container runtimes like gVisor or Firecracker VMs for stronger isolation without creating new clusters.
## Cluster suspension
Managed clusters with no attached compute are automatically suspended to save resources. When suspended, the cluster's control plane is paused — it consumes no compute resources but all configuration, certificates, and state are preserved on disk.
### What happens during suspension
* The control plane stops running (no API server, no scheduler)
* All cluster data is preserved — nothing is deleted
* The cluster appears as **Suspended** in your dashboard
* You are not charged for control plane compute while suspended
### Suspending a cluster
Suspend a running cluster from the dashboard, or call the [suspend endpoint](/api-reference/clusters/suspend-cluster) from the API. A cluster can only be suspended when it has no active machines — delete or suspend its machines first.
### Resuming a cluster
When you request a machine for a suspended cluster, Akua resumes the cluster automatically before provisioning, which takes about 15–25 seconds. You can also resume a cluster manually from the dashboard or the [resume endpoint](/api-reference/clusters/resume-cluster).
### Auto-suspend
Free-tier clusters are automatically suspended when all of these conditions are true:
* No Akua-managed machines attached to the cluster
* No healthy worker nodes in the cluster (nodes disconnected for more than 15 minutes are considered inactive)
Akua checks these conditions every 15 minutes. Pro-tier clusters are not automatically suspended.
Suspension preserves everything about your cluster: installed applications, RBAC rules, secrets, and configuration. When you resume the cluster, it picks up exactly where it left off.
## Related topics
Set up a managed cluster.
Connect compute capacity to your cluster.
Connect your Kubernetes infrastructure.
Organize your clusters and products.
# Add workers
Source: https://docs.akua.dev/clusters/add-workers
Connect compute capacity to your managed cluster to run applications
After creating a managed cluster, you need to add worker nodes where your applications will run. Akua handles all the Kubernetes setup and lifecycle management once you connect your machines.
This page covers manually attached workers for managed clusters. Imported clusters keep worker management with the provider or cluster administrator. For Akua-managed machines and BYOM provisioning, see [Managed machines](/compute/overview).
**Don't want to manage servers?** Akua can [provision and manage machines](/compute/machines) for you. Add compute capacity from the dashboard without needing a separate cloud provider account.
**Testing locally?** Use [Multipass](/clusters/local-testing) for free local testing before buying production servers. Akua's managed control plane can communicate with local workers via tunneling without requiring public IP addresses.
## Prerequisites
* An active managed cluster (status shows "Active" in the dashboard)
* A server or machine to connect (see supported operating systems below)
* Server meets minimum requirements: 2 CPU, 4 GB RAM (4 CPU, 8 GB RAM recommended for production)
## How to add workers
In your [clusters dashboard](https://akua.dev/clusters), click on your cluster and find the **"Quick Actions"** section. Click **"Add a worker"** and copy the bootstrap command.
The command looks like:
```bash Bootstrap command theme={null}
curl -fsSL "https://akua.dev/worker.sh?k0sVersion=..." | sudo bash -s -- -t "your-join-token"
```
**Join token details:** The token expires 30 minutes after generation and can be used multiple times to join multiple machines.
SSH into your server:
```bash SSH to server theme={null}
ssh root@your-server-ip
```
Then execute the bootstrap command you copied from the dashboard. The script automatically installs Kubernetes components, joins the worker to your cluster, and configures networking and security.
Your worker will appear in the dashboard within 1–2 minutes as "Active". You can now start deploying applications to your cluster.
## Automated provisioning with cloud-init
For fully automated worker provisioning, use **cloud-init** when creating the server you plan to attach. The server will automatically join your cluster on first boot, so you don't need to SSH in first.
In your cluster dashboard, click **"Add a worker"** and switch to the **"Cloud-init"** tab. Copy the configuration:
```yaml Cloud-init config theme={null}
#cloud-config
runcmd:
- curl -fsSL "https://akua.dev/worker.sh?k0sVersion=v1.33.1-k0s.0" | bash -s -- -t "your-join-token"
```
When creating a new server in your provider's dashboard, paste the cloud-init into the provider's user-data or startup-script field. Common names include:
* **Hetzner**: "Cloud config" under "Additional features"
* **AWS EC2**: "User data" under "Advanced details"
* **DigitalOcean**: "User data" under "Advanced options"
* **Vultr**: "Cloud-Init User-Data"
* **GCP**: "Automation" → "Startup script"
The server will automatically join your cluster within minutes of booting.
Cloud-init's `runcmd` executes once on first boot only. If you need to re-run the bootstrap (for example, after a reset), you'll need to use the manual command method or recreate the server.
## Revoke a bootstrap token
You can revoke an unused worker bootstrap token from the dashboard or with
`POST /v1/clusters/{id}/worker_bootstraps/{wbs_id}:revoke`. Revocation starts a
background operation: Akua records the token as revoked immediately, then
invalidates the k0s join token when the managed control plane is reachable.
If the cluster is suspended or temporarily unreachable, the operation waits until
the cluster can process the invalidation. If you cancel the operation after the
token is marked revoked, the dashboard keeps the bootstrap in the revoked state,
but the bearer token may still join workers until it expires naturally. Bootstrap
tokens expire within 24 hours.
## Bring your own cloud key (BYOM)
If you have an account with a supported cloud provider, you can connect it to Akua so machines are provisioned in your account directly. This bypasses the machine, CPU, and memory resource quotas, and you pay the provider directly.
To use your own cloud key:
1. Navigate to **Settings → Cloud providers** in your workspace
2. Add an API key for any provider shown as available in the dashboard. Hetzner Cloud is available today.
3. When creating machines from the dashboard, select your cloud provider key
Your machines are created in your cloud account. Concurrency and rate limits still apply because they protect the cluster regardless of who pays for the compute. See [limits and pricing](/clusters/limits#bring-your-own-cloud-key) for full details.
## Supported operating systems
Workers support a wide range of Linux distributions. Windows workers are supported only on mixed operating system clusters; see [Windows workers](/clusters/windows-workers) before attaching a Windows machine.
* **Debian**: 11 (Bullseye), 12 (Bookworm)
* **Ubuntu**: 22.04 LTS or later
* **Red Hat Enterprise Linux**: 7.9, 8.10, 9.5
* **CentOS Stream**: 9, 10
* **Oracle Linux Server**: 8.9, 9.3
* **Amazon Linux**: 2023
* **Fedora**: 41 (Cloud Edition)
* **Fedora CoreOS**: Stable stream
* **Alpine Linux**: 3.19, 3.22
* **Flatcar Container Linux**
* **Windows Server**: 2022 amd64, only with `mixed_os_calico` managed clusters
## Troubleshooting
* Verify the server has internet connectivity
* Check that the setup command was copied correctly
* Ensure you're running as root (with `sudo`)
* Wait 2–3 minutes for the registration process
* Check server meets minimum requirements (2 CPU, 4 GB RAM)
* Ensure you're using a supported Linux distribution or the [Windows worker prerequisites](/clusters/windows-workers#prerequisites)
* Verify no conflicting Docker or Kubernetes installations
* Verify server has outbound networking access to the control plane (outbound HTTPS connections are allowed by default, but check if behind a firewall)
Akua's managed KaaS architecture is designed so workers don't need public IP addresses. Workers automatically create outbound connectivity tunnels to the control plane, allowing the control plane to reach the kubelet securely. This works behind firewalls, NAT, and restrictive networks.
## API
Manage clusters and machines programmatically.
Cluster endpoints including worker bootstrap token generation.
Provision and manage Akua-managed compute machines.
## Related topics
Let Akua provision and manage machines for you.
Test worker setup locally with Multipass before production.
Which limits apply and how BYOM bypasses quotas.
Add persistent storage after your workers are connected.
# Create a cluster
Source: https://docs.akua.dev/clusters/create
Set up a managed Kubernetes cluster in minutes
Create a managed Kubernetes cluster where Akua handles the control plane and all Kubernetes operations, while you maintain control over your infrastructure and billing.
## Prerequisites
* A workspace in Akua
* Access to the [clusters dashboard](https://akua.dev/clusters)
## How to create your cluster
In the [clusters dashboard](https://akua.dev/clusters), click **"Create Cluster"** and choose a region name for organizing your clusters. Regions are custom labels you define to help organize your infrastructure and will be shown to customers when they purchase your products.
Region names are flexible and can be changed anytime. Use descriptive names that make sense for your business, such as "Production", "US-East", "Europe", or "Development".
Choose your cluster configuration:
* **Cluster name**: a descriptive name for your infrastructure
* **Kubernetes version**: latest stable version (recommended)
* **High availability**: multi-zone control plane for production workloads
Click **"Create"** to provision your cluster. The control plane will be ready in 2–3 minutes.
You'll see the status change to "Active" when your cluster is ready for worker nodes.
## API
Manage clusters programmatically.
Endpoints, parameters, response shapes, and try-it playground.
Mint API tokens for programmatic access.
## Related topics
Connect compute capacity to run your applications.
Understand how clusters work in Akua.
Organize clusters into regions for customers.
Which limits apply to clusters and compute.
# Import a cluster
Source: https://docs.akua.dev/clusters/import
Connect your existing Kubernetes infrastructure
If you already have a Kubernetes cluster from any source, you can import it into Akua. This works with any existing cluster — whether it's self-managed, from cloud providers (EKS, GKE, AKS), or other managed Kubernetes services. This lets you leverage your existing investment while gaining access to Akua's product install and marketplace features.
Consider [creating a managed cluster](/clusters/create) instead if you don't already have a Kubernetes cluster set up. Akua handles all the complex control plane management, so you can focus on your product rather than infrastructure operations. With imported clusters, control plane and worker operations are managed by your cloud provider or yourself, depending on your cluster type.
## When to import versus create
Choose to import your cluster if you already have Kubernetes infrastructure from EKS, GKE, AKS, or other providers, have invested in cluster setup, need specific configurations like custom networking or compliance requirements, or want to maintain your existing cluster management approach.
Consider creating a new managed cluster if you want Akua to handle the control plane with zero operational overhead, are new to Kubernetes and want to avoid complexity, prefer simplicity to focus on products rather than infrastructure, or need quick setup to get running in minutes.
## Prerequisites
Before importing your cluster, ensure it meets these requirements:
* **Kubernetes version**: 1.33+ (check with `kubectl version`)
* **Cluster access**: Admin permissions, network connectivity, valid kubeconfig
* **Required permissions**: Namespace management, workload deployment, RBAC operations
If you're not using admin kubeconfig, create a service account with these permissions and bind it to a ClusterRole:
```yaml RBAC configuration theme={null}
apiVersion: v1
kind: ServiceAccount
metadata:
name: akua-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: akua-role
rules:
- apiGroups: ['']
resources: ['pods', 'pods/log', 'pods/exec', 'secrets']
verbs: ['get', 'list', 'watch', 'create', 'update', 'delete']
- apiGroups: ['apps']
resources: ['statefulsets', 'statefulsets/status']
verbs: ['get', 'list', 'watch', 'create', 'update', 'delete']
- apiGroups: ['']
resources: ['namespaces', 'namespaces/finalize']
verbs: ['get', 'list', 'watch', 'create', 'update', 'delete']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: akua-role-binding
subjects:
- kind: ServiceAccount
name: akua-sa
roleRef:
kind: ClusterRole
name: akua-role
apiGroup: rbac.authorization.k8s.io
```
## How to import your cluster
Ensure you have a valid kubeconfig file with admin access to your cluster.
```bash Test cluster connection theme={null}
kubectl cluster-info
kubectl get nodes
```
```bash Export kubeconfig theme={null}
# If using default location
cat ~/.kube/config
# Or specify custom path
cat /path/to/your/kubeconfig
```
In the [clusters dashboard](https://akua.dev/clusters), click **"Import Cluster"** and choose **"Import Existing Cluster"**.
Click "Upload kubeconfig file" and select your kubeconfig file.
Copy your kubeconfig content and paste it into the text area.
Akua will automatically verify cluster accessibility, required permissions, Kubernetes version compatibility, and network connectivity.
If validation fails, check your kubeconfig and cluster permissions before retrying.
Set up how Akua will interact with your cluster: choose a cluster name, set the default namespace where new products will deploy, configure optional resource limits, and enable Akua observability (recommended). Then click **"Import Cluster"** to finalize the process.
Your cluster will appear in the dashboard as "Active" and ready for product installs.
## Limitations of imported clusters
Be aware of these differences compared to managed clusters:
Control plane and worker operations are managed by your cloud provider or yourself, depending on your cluster type. Akua does not manage the control plane for imported clusters.
You manage worker nodes yourself or through your cloud provider. Akua handles product installs but not worker infrastructure management.
You must handle Kubernetes version updates and cluster maintenance yourself. Akua does not automatically update imported clusters.
Limited monitoring compared to managed clusters. Akua provides application-layer monitoring, but infrastructure monitoring is your responsibility.
Not supported through Akua. You must configure and manage auto-scaling through your cloud provider or cluster management tools.
Application layer support only. Akua helps with product installs and troubleshooting, but full infrastructure support is not included.
## Troubleshooting
* Verify cluster is accessible from the internet
* Check that kubeconfig has admin permissions
* Ensure Kubernetes version is 1.33 or newer
* Test connection locally:
```bash Test connection theme={null}
kubectl cluster-info
```
```text Expected output theme={null}
Kubernetes control plane is running at https://xxx.xxx.xxx.xxx:6443
CoreDNS is running at https://xxx.xxx.xxx.xxx:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
```
* Verify cluster API server is publicly accessible
* Check firewall rules allow Akua IP ranges
* Ensure DNS resolution works for your cluster
* Test from external network:
```bash Test API server access theme={null}
curl -k https://your-cluster-api:6443
```
* Confirm kubeconfig has cluster-admin role
* Check RBAC is properly configured
* Verify service account has necessary permissions
* Test permissions:
```bash Test permissions theme={null}
kubectl auth can-i "*" "*" --all-namespaces
```
* Check cluster has adequate resources
* Verify default namespace exists and is accessible
* Review cluster events:
```bash Review events theme={null}
kubectl get events --sort-by=.metadata.creationTimestamp
```
* Contact support with deployment logs
## API
Manage clusters programmatically.
Endpoints, parameters, response shapes, and try-it playground.
Mint API tokens for programmatic access.
## Related topics
Set up a cluster where Akua manages the control plane.
Understand how clusters work in Akua.
Add persistent storage to your cluster.
Organize imported clusters with the rest of your infrastructure.
# Limits and pricing
Source: https://docs.akua.dev/clusters/limits
Which Akua limits apply to clusters, compute, and storage
The following limits apply when provisioning and running managed clusters and machines. For the actual Free / Pro / Enterprise numbers, see the canonical pages linked below. This page only describes scope.
## Limits that apply to clusters
| Limit | Scope | Canonical source |
| ----------------------------------------- | ----------------- | -------------------------------------------------------------------- |
| Managed clusters per user | Resource quota | [Plan comparison →](/pricing#plan-comparison) |
| Compute machines per user | Resource quota | [Plan comparison →](/pricing#plan-comparison) |
| CPU cores and memory | Resource quota | [Plan comparison →](/pricing#plan-comparison) |
| Machine lifetime (Akua-managed) | Resource quota | [Plan comparison →](/pricing#plan-comparison) |
| Concurrent machine provisions per cluster | Concurrency limit | [Quotas → Concurrency limits →](/platform/quotas#concurrency-limits) |
| Cloud-provider API call rate | Rate limit | [Quotas → Rate limits →](/platform/quotas#rate-limits) |
Resource quotas count **per user** across all workspaces. Concurrency limits count **per cluster**.
## Bring your own cloud key
[BYOM machines](/clusters/add-workers) bypass the machine, CPU, and memory resource quotas (you pay the provider directly). Cluster, concurrency, and rate limits still apply because they protect the control plane regardless of who pays for the compute. Full details on the [BYOM section of Quotas](/platform/quotas#bring-your-own-cloud-key-byom).
## Pricing
Cluster and machine costs are part of Akua's plan tiers. Pro includes more headroom and removes the 7-day machine lifetime cap; Enterprise allows custom overrides.
Free vs Pro: included clusters, machines, CPU, memory, and overage pricing.
Custom per-workspace limits, dedicated support, compliance.
How resource, concurrency, and rate limits work end-to-end.
Bypass machine quotas with your own cloud provider key.
## Related topics
Managed and imported Kubernetes infrastructure.
Provision and scale the servers behind your clusters.
Persistent volumes for stateful workloads.
How resource, concurrency, and rate limits work.
# Local testing
Source: https://docs.akua.dev/clusters/local-testing
Test your applications locally with Multipass before deploying to production
Multipass is the perfect tool for testing worker configurations locally without any cloud costs. Built by Canonical specifically for testing scenarios, Multipass lets you quickly spin up Ubuntu VMs on your local machine to test worker setups before buying production machines. It provides free local testing, rapid iteration (quickly create, destroy, and recreate test workers), and production simulation (test exact worker setup procedures in a local environment).
**Performance considerations**: Local testing with Multipass will be slower than production servers due to your home internet connection (typically much slower than datacenter 1–10+ Gbps links) and limited local resources. Ensure your VM has at least 1 CPU and 3 GB RAM for reliable testing.
Akua's managed KaaS architecture is designed so your workers don't need a public IP address. When a worker starts, it automatically creates an outbound Konnectivity tunnel to the control plane, allowing the control plane to reach the kubelet securely.
## Prerequisites
Install Multipass on your development machine:
**Using Homebrew (recommended)**
```bash Install Multipass theme={null}
brew install multipass
```
**Manual download**
Download from [https://multipass.run](https://multipass.run)
Install the .pkg file
```bash Verify installation (macOS) theme={null}
multipass version
```
**Using Snap (recommended)**
```bash Install Multipass theme={null}
# Ubuntu/Debian and most Linux distributions
sudo snap install multipass
```
**Manual download**
Download from [https://multipass.run](https://multipass.run)
Follow distribution-specific installation instructions
```bash Verify installation (Linux) theme={null}
multipass version
```
**Using Chocolatey (recommended)**
```powershell Install Multipass theme={null}
choco install multipass
```
**Manual download**
Download installer from [https://multipass.run](https://multipass.run)
Run the .exe installer
```powershell Verify installation (Windows) theme={null}
multipass version
```
## Setting up a test worker
First, ensure you have an active cluster in your [Akua dashboard](https://akua.dev/clusters). You'll need the worker setup command from this cluster.
Create a new Ubuntu VM with adequate resources for testing:
```bash Create and verify VM theme={null}
# Create VM with recommended specs for testing
multipass launch --name akua-worker --cpus 2 --memory 4G --disk 20G
# Verify VM is running
multipass list
```
Use `--cpus 4 --memory 8G` for more realistic production testing scenarios.
```bash Connect to VM theme={null}
# SSH into the Multipass VM
multipass shell akua-worker
```
You're now inside the Ubuntu VM, ready to test the worker setup.
In your Akua dashboard, navigate to your [active cluster](https://akua.dev/clusters), click the **"Quick Actions"** menu, select **"Add a worker"**, and copy the bootstrap command.
Inside the Multipass VM, run the worker setup command:
The setup will automatically:
* Install Kubernetes components
* Configure networking
* Join the worker to your cluster
* Establish outbound tunnel to control plane
Check your Akua dashboard — the worker should appear as "Active" within 1–2 minutes.
Your test worker is now connected and ready for testing product installs.
## Testing product installs
With your Multipass worker connected, you can test complete product install workflows:
1. **Create test products** in your Akua dashboard
2. **Deploy to test cluster** using your Multipass worker
3. **Verify installs** work correctly
4. **Iterate configurations** without cloud costs
**Product ingress considerations**: If your product exposes services and expects a public IP, you'll need to use your local VM's IP address instead. Get it with `multipass info akua-worker`. This depends on each product's deployment — some products use cloudflared tunnels which work without extra configuration, while others may require manual IP configuration for local testing.
## Cleanup and management
### VM management
```bash Manage VM lifecycle theme={null}
# Stop the VM when not testing
multipass stop akua-worker
# Start it again when needed
multipass start akua-worker
# Delete when done testing
multipass delete akua-worker
multipass purge
```
### Worker cleanup
When you're done testing, remove the worker from your cluster:
1. In the Akua dashboard, go to your cluster
2. Find the Multipass worker in the worker list
3. Remove it to keep your cluster clean
## Advanced testing scenarios
Test multi-worker scenarios by creating multiple VMs:
```bash Create multiple test workers theme={null}
# Create additional test workers
multipass launch --name akua-worker-2 --cpus 2 --memory 4G --disk 20G
multipass launch --name akua-worker-3 --cpus 2 --memory 4G --disk 20G
# Connect each one using the same worker setup command
```
Test with minimal resources to simulate constrained environments:
```bash Create minimal test worker theme={null}
# Minimal test worker
multipass launch --name akua-minimal --cpus 1 --memory 2G --disk 10G
```
Test network scenarios by configuring Multipass networking:
```bash Create network test VM theme={null}
# Custom network configuration
multipass launch --name akua-network-test --network name=bridge
```
## Troubleshooting
* Check available system resources (CPU, RAM, disk)
* Verify Multipass service is running: `multipass version`
* Try with lower resource requirements: `--cpus 1 --memory 2G`
* Ensure VM has internet connectivity: `curl -I https://akua.dev/worker.sh`
* Verify the worker token hasn't expired (30 minutes)
* Try the setup command with `sudo` explicitly
* Wait 2–3 minutes for registration to complete
* Check VM system time is synchronized
* Verify outbound HTTPS connections work
* Check Akua dashboard shows cluster as "Active"
## Related topics
Use the same commands on production servers.
Understand how clusters work in Akua.
Set up a managed cluster to test against.
Add persistent storage to your test cluster.
# Storage
Source: https://docs.akua.dev/clusters/storage
Add persistent storage to your clusters so applications can store data that survives restarts and upgrades
Most applications need to store data that persists beyond the lifetime of a single container: databases, file uploads, caches, and configuration. Kubernetes handles this through persistent volumes, which provide storage that survives pod restarts, upgrades, and rescheduling.
Before your applications can use persistent storage, your cluster needs a StorageClass (a definition of what storage is available and how volumes are created). Akua provides two built-in storage providers you can deploy with one click, or you can use your own.
## Built-in storage providers
Akua includes two storage providers that cover development through production:
Direct local disk storage with the lowest latency. Ideal for development, single-node setups, and databases that handle their own replication.
Replicated block storage across multiple nodes with synchronous or asynchronous replication. Automatic failover on node failure.
## Choosing a provider
The key question is: **who handles data replication, the storage layer or your application?**
| | Local Path Provisioner | Piraeus (LINSTOR) |
| ---------------------- | -------------------------------------- | ---------------------------------------------------- |
| **Replication** | None (your application must handle it) | Storage-level, across nodes |
| **Failover** | Application-managed | Automatic (pods reschedule to a node with a replica) |
| **Volume size limits** | Not enforced (volumes are directories) | Enforced at the block device level |
| **Volume expansion** | Not supported | Supported |
| **Snapshots** | No | Yes |
| **Write latency** | Lowest (direct to local disk) | Depends on replication mode (sync or async) |
If your databases already replicate data across instances (like PostgreSQL streaming replication or MongoDB replica sets), Local Path Provisioner on NVMe SSDs gives you the best raw performance. If you want the storage layer to handle durability for you, use Piraeus.
## Deploy a storage provider
In your [cluster dashboard](https://akua.dev/clusters), select your cluster and navigate to the **Storage** tab.
If no storage provider is installed, you'll see an empty state with a **Deploy Storage** button. Click it to open the provider selection sheet.
Select **Local Path Provisioner** for development or **Piraeus (LINSTOR)** for production. Each card shows the provider's features and trade-offs.
Click **Deploy Storage**. The provider is deployed to your cluster as a standard application. A default StorageClass is created automatically, so your applications can request storage right away.
After deployment, the Storage tab shows your available StorageClasses with their provisioner, reclaim policy, and binding mode.
## Imported clusters
If you're using an [imported cluster](/clusters/import), you may already have storage configured by your cloud provider or infrastructure team:
* **Managed Kubernetes** (EKS, GKE, AKS): these typically come with a default StorageClass backed by cloud block storage (EBS, Persistent Disk, Azure Disk). Check your cluster's Storage tab to confirm.
* **Self-managed clusters**: you can deploy Akua's built-in providers, or use a CSI driver from your infrastructure provider. For example, if your VMs run on Hetzner, consider the [Hetzner CSI driver](https://github.com/hetznercloud/csi-driver) to provision cloud volumes directly.
Akua's built-in providers work on any cluster, managed or imported. If your cloud provider already supplies storage, you don't need to deploy an additional provider unless you want different storage characteristics (like replication across nodes).
## How applications use storage
When an application requests persistent storage through a PersistentVolumeClaim, Kubernetes automatically provisions a volume using your cluster's default StorageClass. Your Package resources declare the storage they need, and the cluster handles the rest.
Common applications that require persistent storage:
* Databases (PostgreSQL, MySQL, Redis, MongoDB)
* File storage and media uploads
* Message queues (RabbitMQ, Kafka)
* Search engines (Elasticsearch, Meilisearch)
## Related topics
Set up a managed cluster to deploy storage on.
Connect compute capacity to your cluster.
Connect your existing Kubernetes cluster.
Understand how clusters work in Akua.
# Local Path Provisioner
Source: https://docs.akua.dev/clusters/storage/local-path
Direct local disk storage for development, single-node setups, and latency-sensitive workloads
Local Path Provisioner uses the worker node's local disk to create persistent volumes. It requires no external dependencies or configuration, and delivers fast I/O since data lives on the same machine as your application.
## When to use
* **Development and testing**: get persistent storage running in seconds
* **Single-node clusters**: local testing with [Multipass](/clusters/local-testing) or a single production server
* **Latency-sensitive production workloads**: databases on NVMe SSDs where direct disk access matters and the application handles its own replication (for example, PostgreSQL with streaming replication or MongoDB replica sets)
* **Simple production setups**: single-node servers where replication isn't needed
Local Path Provisioner stores data on a single node with **no replication**. If the node fails or is replaced, the data is lost. For production workloads that need storage-level durability, use [Piraeus (LINSTOR)](/clusters/storage/piraeus) instead, unless your application handles replication itself.
## How it works
When an application requests storage, Local Path Provisioner creates a directory on the node's local filesystem and mounts it into the pod. The volume is tied to that specific node. If Kubernetes needs to reschedule the pod, it schedules it back to the same node so it can access its data.
**Key characteristics:**
* One volume per PersistentVolumeClaim
* Pods using local storage are pinned to the node where the volume was created
* No network overhead: reads and writes go directly to local disk, providing the lowest possible latency
## Deploy
Navigate to your cluster's **Storage** tab, click **Deploy Storage**, and select **Local Path Provisioner**. The provider deploys in under a minute and creates a default StorageClass automatically.
After deployment, any application that requests a PersistentVolumeClaim will get a local volume provisioned on the node where the pod is scheduled.
## Limitations
* **Single-node only**: data lives on one node and is not replicated
* **No failover**: if the node goes down, pods using local storage can't be rescheduled elsewhere until the node recovers
* **No snapshots**: volume snapshots are not supported
* **No volume size enforcement**: requested storage sizes in PersistentVolumeClaims are not enforced. Since each volume is just a directory on the node's filesystem, it can grow to use all available disk space regardless of the size you request ([GitHub #107](https://github.com/rancher/local-path-provisioner/issues/107)).
* **No volume expansion**: resizing a PVC after creation is not supported. Attempting to expand a volume causes the controller to log repeated errors because the provisioner has no resize capability ([GitHub #190](https://github.com/rancher/local-path-provisioner/issues/190)).
* **Node affinity**: pods are pinned to the node where their volume was created
## Local storage in production
Local Path Provisioner can be a valid production choice when your priority is raw disk performance and your application handles data replication at the application level. Databases like PostgreSQL, MySQL, and MongoDB have built-in replication that keeps copies of data across multiple instances; they don't need the storage layer to replicate for them. In these cases, local storage on NVMe SSDs gives you the lowest latency without the overhead of network-based replication.
The trade-off is operational: you're responsible for ensuring your application's replication is configured correctly. If it isn't, a node failure means data loss.
## Moving to replicated storage
When you want storage-level replication instead of managing it at the application layer:
1. Deploy [Piraeus (LINSTOR)](/clusters/storage/piraeus) for replicated storage across nodes
2. Migrate your data by backing up and restoring from the application level (database dumps, file exports)
3. Remove Local Path Provisioner once all workloads have moved
You can run both storage providers simultaneously during migration. Set Piraeus as the default StorageClass, and new volumes will automatically use replicated storage while existing local volumes continue to work.
## Related topics
Production-grade replicated storage across multiple nodes.
Compare providers and deploy storage to your cluster.
Connect worker nodes that provide local disk for this provider.
Project source and upstream documentation.
# Piraeus (LINSTOR)
Source: https://docs.akua.dev/clusters/storage/piraeus
Replicated block storage across multiple nodes for production workloads
Piraeus is a production-grade storage solution built on LINSTOR and DRBD. It replicates data across multiple worker nodes, so if a node fails, your applications continue running on another node with a complete copy of their data.
## When to use
* **Production workloads**: databases, message queues, and any application where data loss is unacceptable
* **Multi-node clusters**: two or more worker nodes for meaningful replication
* **High availability**: applications that need to survive node failures without downtime
## How it works
Piraeus runs a storage controller and satellite agents on your worker nodes. When an application requests a volume:
1. LINSTOR creates a block device and replicates it across multiple nodes
2. DRBD keeps replicas synchronized in real time at the kernel level
3. If the primary node fails, Kubernetes reschedules the pod to a node with an up-to-date replica
4. The application resumes with all its data intact, with no manual recovery needed
**Key characteristics:**
* Configurable replication (synchronous by default, with asynchronous options for performance-sensitive workloads)
* Automatic failover: pods reschedule to healthy nodes with existing replicas
* Volume snapshots and cloning for backup and testing
* Thin provisioning: storage is allocated on demand, not reserved upfront
## Replication modes
DRBD supports three replication protocols that control when a write is considered complete:
| Protocol | Mode | Write confirmed when | Best for |
| -------------- | ---------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
| **Protocol C** | Synchronous | Local **and** remote disk writes complete | Most workloads; strongest data safety (default) |
| **Protocol B** | Semi-synchronous | Local disk write completes and data reaches the peer node's memory | Faster writes with near-synchronous safety |
| **Protocol A** | Asynchronous | Local disk write completes and data is placed in the send buffer | Maximum write performance, useful for long-distance replication or disaster recovery |
**Protocol C** (synchronous) is the default and the right choice for most production workloads. Every write is confirmed on both nodes before your application proceeds, so no data is lost if a node fails.
**Protocol A** (asynchronous) gives you significantly faster write performance because the application doesn't wait for the remote node to confirm. The trade-off is that a small window of recent writes could be lost if the primary node fails before the data reaches the replica. This mode is commonly used for disaster recovery across data centers where the network latency of synchronous replication would be too high.
## Deploy
Navigate to your cluster's **Storage** tab, click **Deploy Storage**, and select **Piraeus (LINSTOR)**. Deployment takes a few minutes as Piraeus installs its controller and satellite components on each worker node.
After deployment, a default StorageClass is created. Any application requesting a PersistentVolumeClaim will get a replicated volume distributed across your nodes.
## Worker node storage
Piraeus uses the local disks on your worker nodes for storage. When choosing servers for a cluster with Piraeus:
* **Disk space**: each node contributes its local disk to the storage pool. More disk space per node means more total storage capacity.
* **Disk type**: NVMe SSDs provide the best performance for database workloads. Standard SSDs work well for most applications.
* **Number of nodes**: at least two for meaningful replication, three for full redundancy (data survives any single node failure).
Using your worker nodes' local disks is the most straightforward and cost-effective approach. You avoid provisioning separate cloud volumes, and Piraeus handles replication automatically. This works well for most workloads: production-grade durability without extra infrastructure costs.
## Cloud provider CSI drivers
If your worker nodes run on a cloud provider with its own block storage (Hetzner Cloud Volumes, AWS EBS, etc.), you have a choice:
* **Piraeus with local disks**: simpler setup, no cloud-specific dependencies, replication handled by DRBD. Your data is replicated across nodes regardless of the underlying cloud provider.
* **Cloud CSI driver**: uses the cloud provider's managed block storage. The cloud provider handles durability and snapshots, but you pay per volume and are tied to that provider.
Both approaches are valid. Piraeus with local disks is provider-agnostic and keeps your infrastructure portable. A cloud CSI driver may be preferable if you want cloud-managed snapshots or your provider offers specialized storage tiers.
Akua's built-in Piraeus deployment works on any cluster: managed or imported, any cloud provider or bare metal. You don't need to choose a storage strategy based on your infrastructure provider.
## Related topics
Direct local disk storage for development and latency-sensitive workloads.
Compare storage providers and deploy to your cluster.
Connect compute capacity to provide local disk for Piraeus.
Project source and upstream documentation.
# Windows workers
Source: https://docs.akua.dev/clusters/windows-workers
Attach Windows Server workers to mixed operating system managed clusters
Windows workers let you attach customer-owned Windows Server machines to a managed cluster. This page covers native Windows Server workers for managed clusters. It does not cover imported clusters, Docker Desktop, Windows-only Kubernetes clusters, or running Linux workloads as Windows containers.
Windows workers require a managed cluster created with the `mixed_os_calico` network profile. This profile is currently enabled through Akua-supported setup or the Clusters API, not the default dashboard cluster creation path.
## Supported launch path
Akua supports Windows workers only when all of the following are true:
* The machine runs **Windows Server 2022 amd64**.
* The cluster was created with the `mixed_os_calico` network profile.
* The cluster has a Linux control plane and at least one Ready Linux worker for Linux workloads and system capacity.
* The Windows worker can reach the managed control plane and the other workers over the required network paths.
Windows support is a cluster capability, not a package compatibility guarantee. Linux-only packages still need Linux worker capacity in the same cluster. A package can run on Windows only when the package publishes Windows-compatible images, commands, probes, volumes, and Kubernetes placement rules.
## Unsupported at launch
The following configurations are not supported for the current Windows worker launch:
* Windows ARM64 workers.
* Windows Server 2019 or Windows Server 2025 workers.
* Windows-only managed clusters.
* Cilium-backed Windows worker clusters.
* Air-gapped or offline worker bootstrap.
* Linux container images running as native Windows workloads.
## Prerequisites
* Administrator PowerShell access on the Windows Server.
* Windows Containers feature enabled, or permission to enable it and reboot before joining.
* Outbound access from the worker to the Akua control plane and bootstrap artifacts.
* Konnectivity TCP 8132 reachability from the worker to the control plane path.
* Calico VXLAN UDP 4789 reachability between workers.
* Kubelet TCP 10250 reachability where your cluster topology requires it.
* Pod and service CIDR reachability for the cluster network.
## Add a Windows worker
Use a managed cluster created with `mixed_os_calico`. If you don't already have one, coordinate with Akua support or use the Clusters API to create the cluster with that network profile.
Open the cluster worker page or the install wizard compute step, then select **Windows Server** as the worker platform.
Copy the generated PowerShell bootstrap command. The command is tied to a short-lived bootstrap token.
Run the command in an elevated PowerShell session on the Windows Server.
Wait for the worker to appear as Ready in the dashboard.
The bootstrap token is short-lived. If the token expires before the worker joins, generate a new worker bootstrap command from the dashboard.
## Workload placement
In mixed operating system clusters, packages must state where workloads run. If a package is Linux-only, add or keep Linux capacity in the same cluster. Adding a Windows worker does not move Linux workloads onto Windows.
## Related topics
Attach compute capacity to a managed cluster.
Understand managed and imported clusters.
# Commerce
Source: https://docs.akua.dev/commerce
Sell products, share private offers, and guide customers through checkout
Commerce is how Akua turns products into customer purchases and installations. You can publish products in a marketplace, send private offers, route customers through checkout, and track order drafts until the product is running.
Use this section when you want to sell software, onboard customers, or give partners a controlled install path.
Understand public catalog listings and private offer distribution.
Configure the sellable software customers install.
Share short links with pre-filled configuration and access rules.
Connect Stripe and understand checkout settlement.
## Common paths
* Create a [Product](/products) before publishing or sharing an offer.
* Use [Offers](/marketplace/offers) for private sales, partners, and customer-specific configuration.
* Read [Order drafts](/marketplace/order-drafts) when you need to understand the checkout-to-install flow.
# Compute
Source: https://docs.akua.dev/compute
Provision, autoscale, suspend, and manage the machines that run your workloads
Compute is the machine layer behind your clusters. Today, Akua-managed compute and bring-your-own cloud key provisioning start with Hetzner Cloud. You can also attach existing workers manually when you want to keep your own infrastructure.
Use this section when you need to understand how applications get capacity, how machines scale, and how bring-your-own infrastructure fits into Akua.
Understand the Kubernetes layer where workloads run.
Review Akua-managed machines, bring-your-own cloud key provisioning, and manual worker paths.
Inspect lifecycle states, drift, suspension, and deletion behavior.
Configure Hetzner Cloud regions and credentials.
## Common paths
* Create a [managed cluster](/clusters/create) when you want Akua to operate Kubernetes for you.
* Read [Managed machines](/compute/overview) when you want Akua-managed machines, BYOM credentials, or the current compute paths.
* Use [Add workers](/clusters/add-workers) when you want to attach your own machines manually.
# Machines
Source: https://docs.akua.dev/compute/machines
Akua-managed compute that provisions and manages worker nodes for you
When you create a managed cluster, you need worker nodes to run your applications. Akua can provision and manage these machines for you. Create a machine from the dashboard, and Akua handles the rest: server creation, Kubernetes setup, cluster joining, and lifecycle management.
You can also [add your own workers manually](/clusters/add-workers) by running a bootstrap command on any Linux server. Akua-managed machines are an alternative that removes the need for a separate cloud provider account.
## Machine lifecycle
### Provisioning
When Akua provisions a machine for your cluster:
1. Akua creates a cloud server using the resolved compute config for your cluster's region.
2. The server bootstraps automatically and joins your cluster.
3. The machine appears in your dashboard with real-time status updates.
4. Akua monitors the machine and handles its full lifecycle.
You can track each machine's progress through four stages: **Provisioned** (server created), **Bootstrapped** (Kubernetes installed), **Joined** (connected to cluster), and **Ready** (accepting workloads).
If your cluster is [suspended](/clusters#cluster-suspension) when a machine is requested, Akua resumes the cluster automatically before provisioning begins. This adds approximately 15–25 seconds while the control plane starts up.
### Auto-scaling
Akua automatically matches capacity to your workload requirements. When your cluster needs more resources, new machines are provisioned. When demand decreases, idle machines are removed to reduce costs.
**Concurrency limit:** To prevent runaway provisioning loops, Akua limits how many machines can be launching at once per cluster: 1 on the free plan and 3 on Pro. If your cluster requests more machines than this limit, they are queued and provisioned as earlier machines complete. If provisioning repeatedly fails (for example, due to a provider capacity issue), Akua backs off to avoid unnecessary retries. See [quotas](/platform/quotas) for details.
**Auto-scaling controls:** You can pause and resume auto-scaling from the **Machines** tab. When paused, no new machines are created regardless of pending workloads. The current machine count and limit are shown in the header.
When you pause auto-scaling, existing workloads continue running on current machines. New pods that require additional capacity will remain pending until auto-scaling is resumed.
### Deletion
When a machine is deleted (not suspended), the data is permanently removed:
1. Running workloads are gracefully drained off the machine (up to 2 minutes).
2. The cloud server is deleted and billing stops immediately.
3. Cluster resources are cleaned up.
If your workloads still need resources after deletion, auto-scaling may provision a new machine to replace it, unless you have paused auto-scaling or your quota is at its limit.
If the cluster is unreachable (for example, during cluster deletion), Akua skips the drain step and deletes the cloud server directly to stop billing immediately.
### Free tier machine lifetime
Akua-managed machines on the free tier are automatically deleted after 7 days. You receive email and [dashboard notifications](/platform/notifications) at 5 days, 2 days, and 24 hours before deletion.
BYOM machines are not subject to the 7-day lifetime. They run as long as you leave them running, because you pay the cloud provider directly.
To keep managed machines running longer, add your own cloud key or upgrade to Pro. See [plans and pricing](/pricing) for details.
## Suspend and resume
Suspend a machine to stop paying for compute while preserving its data. Machine suspend and resume controls are part of the machine lifecycle rollout; this page documents the machine fields and provider behavior that support that lifecycle.
## Provider resource identity
The machine's `provider_resource` object exposes how the underlying cloud resource behaves across suspend and resume:
| Field | Values | Meaning |
| --------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider_resource.identity_kind` | `recyclable` | The cloud server is deleted on suspend and replaced on resume. The public IP changes on every resume. Applies to Hetzner, DigitalOcean, Vultr, Linode, OVH. |
| `provider_resource.identity_kind` | `persistent` | The cloud instance is stopped, not replaced. The public IP is stable across stop and start. Applies to AWS, GCP, Azure. |
| `provider_resource.public_ip` | string | The machine's current public IP. Refreshes after each resume on `recyclable` providers. |
| `provider_resource.floating_ip` | object (optional) | A stable IP that survives the suspend and resume cycle. Not yet implemented. |
Use the `identity_kind` field to show an appropriate warning before a user suspends a `recyclable` machine that has no `floating_ip` attached.
## Supported providers
| Provider | Regions | Status |
| ------------- | -------------------------------------------------------------- | --------- |
| Hetzner Cloud | EU (Falkenstein, Nuremberg, Helsinki), US (Ashburn, Hillsboro) | Available |
More providers are coming. You can also [bring your own cloud key](/compute/overview#bring-your-own-key-byom) to use any supported provider with your own account.
## Notifications
Akua sends notifications for machine lifecycle events such as upcoming expiry. Notifications appear both via email and in the notification center in your dashboard header. See [notifications](/platform/notifications) for details.
## API
Manage machines programmatically.
Create, list, get, update, delete, suspend, and resume machines.
Manage BYOM compute configurations.
## Related topics
Understand managed compute, BYOM, and lifecycle constraints.
Regions, instance types, and Hetzner-specific behavior.
Attach your own servers without Akua-managed provisioning.
Compare plans and understand machine limits.
# Compute
Source: https://docs.akua.dev/compute/overview
Provision and manage cloud servers for your Kubernetes clusters
Akua provisions and manages compute resources: the cloud servers that run your workloads. Managed compute and BYOM provisioning use the providers available in your dashboard; Hetzner Cloud is available today. You don't need a separate cloud provider account to get started, and you can still attach existing workers when that better fits your setup.
## How it works
Akua scales your compute automatically. When your workloads need more resources, Akua detects unschedulable pods and provisions a new server. When demand drops, idle servers are removed to save costs.
```
Pod needs resources → Akua provisions a server → Server joins the cluster → Pod scheduled
```
The entire flow takes about 2 minutes from pending pod to running workload.
Akua keeps the setup simple. Your workspace plan and cluster settings determine which regions, credentials, and instance types are available, so you only choose what you need.
## Three compute paths
### Akua-managed machines
Akua provisions servers for you in Hetzner Cloud. No cloud credentials are required. Machines are subject to [plan quotas](/platform/quotas) and [billing](/billing/overview).
| Plan | Machines | CPU | Memory | Instance types | Machine lifetime |
| ---- | -------- | ------- | ------ | -------------- | ---------------- |
| Free | 1 | 2 cores | 4 GB | Small only | 7 days |
| Pro | 3 | 8 cores | 16 GB | All available | No limit |
### Bring your own cloud key
Add your own supported cloud provider key and Akua provisions machines in your account. You pay the provider directly, with no machine quotas, no lifetime limits, and access to any instance type your account supports.
Go to **Compute** in the dashboard and click **Add Credential**. Akua validates the token before saving it.
Click **Create Config**, select your credential, choose a region, and name the configuration.
Akua uses your config to provision machines in your cloud account when your workloads need resources.
Akua stores the credential securely and re-validates it periodically. You'll get a dashboard notification if the credential becomes invalid.
### Manually attached workers
Attach an existing server to a managed cluster when you want to keep full ownership of the machine without using managed machine provisioning. Use the worker bootstrap command or the cloud-init path in [Add workers](/clusters/add-workers). Imported clusters keep worker management with their provider or cluster administrator.
## Provisioning limits
Akua enforces limits at two levels to keep your infrastructure predictable:
* **Allocation quota**: how many machines your workspace can own (free: 1, pro: 3). BYOM machines are exempt.
* **Concurrency limit**: how many machines can be launching at once per cluster (free: 1, pro: 3). This prevents runaway provisioning loops from multiplying in-progress requests.
Both limits are enforced server-side and take effect immediately when your plan changes, with no cluster reconfiguration needed.
See [quotas](/platform/quotas) for the full table of limits per plan.
## Supported providers
Current managed compute and BYOM provider details.
AWS, GCP, Azure, DigitalOcean, Vultr (planned).
## What's next?
Lifecycle, provisioning, deletion, and auto-scaling controls.
Regions, instance types, and pricing.
Understand resource limits per plan.
## Related topics
Use a bootstrap command to attach your own servers.
Understand how clusters work and how compute fits in.
Compare plans and understand machine limits.
Manage machines programmatically.
# Hetzner Cloud
Source: https://docs.akua.dev/compute/providers/hetzner
EU and US cloud servers — the first compute provider supported by Akua
Hetzner Cloud is the first and default provider for Akua-managed machines today. Hetzner offers high-performance cloud servers at significantly lower prices than hyperscalers, with data centers in Europe and the United States.
## Regions
| Region | Location | ID |
| ----------- | ------------------ | ------ |
| Falkenstein | Germany (Bavaria) | `fsn1` |
| Nuremberg | Germany (Bavaria) | `nbg1` |
| Helsinki | Finland | `hel1` |
| Ashburn | US East (Virginia) | `ash` |
| Hillsboro | US West (Oregon) | `hil` |
The default region for Akua-managed machines is **Falkenstein (fsn1)**.
## Instance types
Akua filters available instance types based on your plan. Available types in each region are verified against Hetzner's datacenter availability (not just pricing data), so the types shown are guaranteed to be provisionable.
### Free tier
| Type | CPU | Memory | Disk | Architecture | Price per hour |
| ------- | ------ | ------ | ----- | --------------- | -------------- |
| `cax11` | 2 vCPU | 4 GB | 40 GB | ARM64 | €0.004 |
| `cx23` | 2 vCPU | 4 GB | 40 GB | x86 | €0.006 |
| `cpx22` | 3 vCPU | 4 GB | 80 GB | x86 (dedicated) | €0.008 |
### Pro tier
All Hetzner Cloud server types are available, including:
| Type | CPU | Memory | Disk | Architecture | Price per hour |
| ------- | ------ | ------ | ------ | --------------- | -------------- |
| `cax21` | 4 vCPU | 8 GB | 80 GB | ARM64 | €0.007 |
| `cax31` | 8 vCPU | 16 GB | 160 GB | ARM64 | €0.013 |
| `cx33` | 4 vCPU | 8 GB | 80 GB | x86 | €0.011 |
| `cx43` | 8 vCPU | 16 GB | 160 GB | x86 | €0.021 |
| `cpx32` | 4 vCPU | 8 GB | 160 GB | x86 (dedicated) | €0.016 |
ARM64 types (`cax*`) offer the best price-to-performance ratio. Use them unless your workloads require x86.
### BYOM (bring your own cloud key)
All instance types available in your Hetzner Cloud account, with no restrictions.
## Billing model
Hetzner bills per hour, rounded up. Servers are billed as long as they exist, **even when powered off**. Akua's machine lifecycle model uses snapshots and server deletion for suspend flows rather than simply stopping the server.
| State | Cost (cx23, 40 GB) |
| -------------------- | --------------------------------------------------- |
| Running | \~€4.11/month |
| Powered off | \~€4.11/month (Hetzner bills for the server object) |
| Suspended (snapshot) | \~€0.40/month (snapshot storage at €0.01/GB) |
| Deleted | €0/month |
## Snapshot pricing
Hetzner charges **€0.01 per GB per month** for snapshots. Snapshots are compressed; you pay for actual used space, not total disk capacity.
| Disk size | Snapshot cost per month |
| --------- | ----------------------- |
| 40 GB | \~€0.40 |
| 80 GB | \~€0.80 |
| 160 GB | \~€1.60 |
## How Akua provisions machines on Hetzner
1. Akua creates a server via the Hetzner Cloud API with a cloud-init script.
2. The cloud-init script installs Kubernetes, configures the worker, and joins your cluster.
3. The machine appears in your dashboard within approximately 2 minutes.
4. Akua monitors the machine and handles its full lifecycle: scaling, suspend, and deletion.
Akua uses its own Hetzner Cloud API token for managed machines. For BYOM, your token is used instead.
## Add your own Hetzner account (BYOM)
In the [Hetzner Cloud Console](https://console.hetzner.cloud/), create an API token with **Read and Write** permissions.
Go to **Compute** in the Akua dashboard, click **Add Credential**, and paste your token. Akua validates it immediately.
Click **Create Config**, select your credential, and choose a region.
Machines provisioned with this config appear in your Hetzner Console and bill to your account. No machine quotas or lifetime limits apply to BYOM machines.
Your API token is stored securely in an external secrets manager. Akua re-validates all tokens hourly and notifies you if a token becomes invalid (for example, if it was revoked or expired in the Hetzner Console).
## Suspend and IP volatility
When you suspend a machine on Hetzner, Akua snapshots the disk and deletes the cloud server. On resume, a brand-new server is provisioned from the snapshot. This means the **public IP address changes on every resume**. Hetzner has no stop state that preserves the IP and instance.
If you need a stable public IP across suspend and resume cycles, use a floating IP, short-TTL DNS, or a load balancer in front of the machine.
## Limitations
* **No Hetzner Volume attachment on suspend and resume**: Hetzner Volumes use server IDs for attachment. If you use Hetzner CSI Volumes (not local storage or LINSTOR), additional steps may be needed on resume. Local storage and LINSTOR volumes work without issues.
* **Powered-off servers still bill**: Unlike AWS and GCP, stopping a Hetzner server does not reduce costs. Use Akua's suspend feature instead.
* **IPv6 only on some instances**: The most affordable Hetzner plans may include IPv6 only. Akua handles this through the cluster's internal networking.
## Related topics
Full machine lifecycle including provisioning, suspension, and deletion.
Akua-managed machines, BYOM keys, and manual worker paths.
Compare plans and understand instance type access.
# Concepts
Source: https://docs.akua.dev/concepts
How packages, dependencies, products, and installations fit together
Akua turns your application into per-customer installs through a small set of primitives. This page lays them out so you can predict what happens at each stage, across any surface: dashboard, CLI, API, or git.
## The flow at a glance
```mermaid theme={null}
%%{init: {'flowchart': {'nodeSpacing': 60, 'rankSpacing': 70, 'curve': 'basis'}}}%%
flowchart TB
subgraph WATCH["Dependencies — packaged content"]
direction LR
HW["Helm chart"]
DI["Container image"]
end
AUTHORED["Author a Package directly"]
PKG["Package
akua.toml + package.k
+ input schema"]
WATCH -. supplies deps .-> PKG
AUTHORED --> PKG
PKG --> P["Product"]
PKG --> SI["Direct install"]
P --> OFFER["Offer
short URL + terms"]
OFFER -- customer purchases --> INS["Installation"]
SI -- creates --> INS
INS -- materializes --> REPO[("Per-install
repository")]
REPO --> K8S["Cluster syncs
rendered manifests"]
```
A Package is the versioned install contract. You can author one directly, then declare supported dependencies such as Helm charts, container images, or other Packages. Products wrap a Package for sale; Offers carry the concrete customer path, terms, access rules, and short URL. Direct installs use a Package internally. When a customer installs, Akua materializes the Package into a per-installation git repository: the customer's specific copy, with their inputs and rendered manifests.
## The primitives
### Package
The versioned install contract, and the canonical primitive. A Package describes how to turn customer inputs and upstream dependencies into Kubernetes resources for an installation. It contains:
* **`akua.toml`**: package metadata and a list of upstream dependencies (Helm charts, container images, other Packages)
* **`package.k`**: composition logic in KCL that turns inputs into resources; can `import` declared dependencies and patch any field on rendered output
* An **input schema**: what customers can configure
A Package is portable on its own. Akua doesn't need to know where the dependencies originally came from to render and deploy it. The `akua.toml` is the contract.
### Dependencies
Upstream content that a Package vendors or references. What the version represents depends on the dependency type:
* **Helm chart**: A reference to a chart on Artifact Hub, an OCI registry, or git. The Package's `akua.toml` pins which chart version to vendor; bumping the chart is a Package-version change.
* **Container image**: A reference to an OCI image used by the Package's Kubernetes resources. Changing the tag is an input or Package-version change, depending on how the Package author exposes it.
* **Package**: A reusable dependency imported by another Package.
Dependencies are wiring, not the install contract. The install contract lives in the Package's `akua.toml` and `package.k`; dependencies are the upstream content the Package renders from. The simple flow is: author a Package, declare dependencies, then ship it.
### Product
A sellable wrapper around a Package: marketplace metadata, selected Package version, and product-level defaults. Products can appear in the marketplace or stay private behind Offers.
Use a Product when you want to sell software. For internal tools, use a Direct install instead.
### Offer
A customer-facing sales path for a Product or Package version. An Offer owns the short URL, access rules, pre-filled field values, expiry, and commercial terms for a specific customer or reusable link.
Use an Offer when you want to send a customer directly into the generated install wizard.
### Direct install
An installation that uses a Package without product wrapping. No pricing, not listed in the marketplace. Same Package, just used internally.
### Installation
A specific running installation in a workspace. Two flavors:
* **Product-based installation**: created when a customer purchases a Product; inherits the Product's defaults and supports per-install overrides on top.
* **Direct installation**: created directly without a Product; owns its inputs 1:1.
Both flavors materialize the Package into a per-install repository.
### Per-install repository
The materialized Package for one installation: a private git repository owned by the customer's workspace.
| File | What it holds |
| ------------- | ------------------------------------------------------------------------------- |
| `akua.toml` | Package metadata and upstream dependencies (copied from the Package definition) |
| `package.k` | Composition logic (copied from the Package definition) |
| `inputs.yaml` | The customer's configured inputs |
| `upstream/` | Vendored copies of the dependencies at provision time |
| `manifests/` | Rendered Kubernetes resources (your cluster syncs these) |
The wizard, the CLI, and accepted repository changes all edit the same repository. Re-rendering is pure: identical inputs always produce identical manifests, so equivalent edits don't churn installs.
See [Installation repositories →](/installs/repositories) for the full model.
## How updates flow to customers
An update is any change to a Package: its inputs, its `package.k` composition, or its `akua.toml` pinned dependencies. The change might come from the seller editing a Product, the customer editing their install's inputs, or an automated bump (a fresh GitHub-built image landing as a new tag, or a new Helm chart version pinned in `akua.toml`). All of them are Package-level edits.
Once a Package change happens, Akua propagates it:
1. **Per-install re-render**: each affected installation gets a fresh render of the new Package against its own `inputs.yaml`, written to its own repository.
2. **Customer overrides preserved**: install-specific overrides on top of product defaults survive the re-render; only what changed in the Package flows through.
3. **Independent rollout**: each install advances on its own commit history; a failed render on one customer's install doesn't block the others.
4. **Pinning respected**: if an install is pinned to an older Package version, the bump skips it until the customer (or seller) chooses to upgrade.
To the seller, updating customers is a single decision: edit the product's defaults or composition and ship the new Package version. To the platform, it's a fan-out. Every installation re-renders and converges on its own schedule.
## What builds on what
| Layer | What it owns | Per-customer? |
| ---------------------------- | ----------------------------------------------------------------- | -------------------------- |
| **Dependencies** | Upstream content a Package vendors or references | No (shared) |
| **Package** | Composition logic, dependencies, input schema | No (shared) |
| **Product / Direct install** | Selected Package + default inputs | No (shared) |
| **Offer** | Customer path, access rules, field values, and commercial terms | No (shared until redeemed) |
| **Installation** | A specific running installation in a workspace | Yes |
| **Per-install repository** | Materialized Package: vendored deps + inputs + rendered manifests | Yes |
Customer A and Customer B can install the same Product and get isolated repositories with different inputs, different version pinning, and independent deploy histories. A change you make for Customer A stays scoped to their repository.
## Customization surfaces
Three surfaces edit the same state:
* **Dashboard wizard**: a form view over the Package's input schema, generated from the `Input` schema and any [`@ui` annotations](/akua/package-format#ui-annotations) the author added
* **CLI / API**: programmatic access to the same inputs
* **Repository change requests**: reviewed edits to the installation's repository
The wizard writes to `inputs.yaml`. Accepted repository changes update the same install state, and Akua re-renders after each accepted change. For edits the wizard doesn't expose (patching individual fields, adding sidecars, swapping image registries), see [Customize an installation via git →](/installs/install-repo).
Sellers control the wizard's presentation by writing docstrings and `@ui` annotations on their `Input` schema. The same schema drives shareable [Offers](/marketplace/offers) at `/i/`.
## Related topics
The per-install git repo: what's inside and why it's there.
The sellable wrapper with marketplace metadata.
Short customer URLs with selected inputs and terms.
Edit inputs, patch resources, and review repository changes.
Get your first product live in minutes.
# Customizing values
Source: https://docs.akua.dev/customizing-values
Configure and customize your applications using inputs and per-installation overrides
Inputs let you customize how an application deploys without modifying its underlying source. Akua provides a wizard-driven editor that lets you configure applications, manage changes, and control how updates roll out to installations.
For most customers, the dashboard's wizard is all you need. For advanced edits — patching individual fields, adding sidecars, overriding what the schema doesn't expose — see [Customize an installation via git](/installs/install-repo). Both surfaces edit the same underlying state: the wizard writes to your installation's `inputs.yaml`, and accepted repository changes update that same state.
## Understanding inputs
Inputs are YAML configuration that drive how an application is rendered for a specific installation. They control everything from resource allocations and scaling behavior to application-specific settings and networking configuration.
When you customize inputs, Akua:
* Writes the change to the installation's `inputs.yaml`
* Re-renders the deployment manifests against the package's composition logic
* Validates inputs against the package's input schema when available
* Commits the new render to the installation's [package repository](/installs/repositories)
The wizard and repository review path are two views over the same state. UI edits and accepted repository changes converge on the same `inputs.yaml`.
## Multi-source configuration
Many applications combine multiple package sources — for example, a web application with a database, cache, and monitoring stack. Akua's editor provides a tabbed interface where you configure each source independently while applying all changes in a single transaction.
### Using the multi-source editor
When editing inputs for products or installations with multiple sources:
1. **Switch between sources** using the tabs at the top of the editor
2. **Edit each source** independently in YAML or form view
3. **Track modifications** with visual indicators (orange dots) on tabs that have been changed
4. **Apply all changes** at once with the "Apply All" button
The editor shows:
* **Modified badge** - Count of sources with unsaved changes
* **Source tabs** - All sources displayed as switchable tabs
* **YAML/Form toggle** - Switch between raw YAML and guided form interface
* **Diff highlighting** - See exactly what differs from defaults
The form view provides a structured interface when the package exposes a JSON Schema. Use YAML view for advanced configurations or sources that don't expose a schema.
## Product inputs and install inputs
Akua distinguishes between **product-level inputs** (the package definition shared across installations) and **install-level inputs** (per-installation customization). Understanding this distinction is crucial for managing updates effectively.
### Product inputs
Product inputs define the default configuration for all future installations. When you update product inputs:
1. **Package definition updated** - The new configuration becomes the default for new installs
2. **Existing installs unchanged** - Current installs continue running on their current package
3. **New installs use updated inputs** - Future installations get the new defaults
4. **Manual rollout required** - You control when existing installs upgrade
**Use product inputs when:**
* Setting default configuration for all customers
* Preparing new features or settings
* Testing changes before wide rollout
* Managing staged installs
### Direct install inputs
Direct installations have their own package definition (1:1 relationship). When you update inputs for a direct install:
1. **`inputs.yaml` updated immediately** - Changes are written to the installation's repository
2. **Re-rendered** - The new configuration is rendered into the installation's `manifests/`
3. **Application redeploys automatically** - The new configuration is applied to your cluster
4. **Single installation affected** - Only this specific install changes
**Use direct install inputs when:**
* Configuring customer-specific installations
* Making one-off customizations
* Testing configurations for specific environments
* Managing independent installs
### Product-based install overrides
Product-based installations support **per-install input overrides** that layer on top of product defaults. When you customize inputs for a product-based install:
1. **Overrides stored separately** - Your customizations are saved as install-specific overrides
2. **Product defaults preserved** - The product's package definition remains unchanged
3. **Inputs merged automatically** - Product defaults + install overrides are merged into `inputs.yaml`
4. **Updates persist** - Overrides survive product updates
5. **Application redeploys** - The new merged configuration is applied to your cluster
**Use product-based install overrides when:**
* Customizing installations for specific customers (custom domains, branding, resource limits)
* Enabling customer-specific features or toggles
* Adjusting configurations per environment (production vs staging)
* Maintaining customer settings across product updates
Install overrides always take precedence over product defaults. When you update the product, customer overrides are automatically merged with the new defaults, ensuring customizations persist.
## Input layering and merging
Akua uses a layered approach to merge inputs from multiple sources, ensuring predictable and maintainable configurations.
### Merge order
Inputs are merged in the following order (later layers override earlier ones):
1. **Upstream defaults** - Defaults defined in the package's source
2. **Product inputs** - Defaults configured at the product level
3. **Install overrides** - Customer-specific overrides for product-based installs
4. **Install metadata** - System-generated values like the installation ID, which is available in your package's composition logic via the install's metadata context
### Deep merging
Akua performs deep merging of nested objects:
```yaml theme={null}
# Product inputs
database:
host: "prod-db.example.com"
port: 5432
ssl: true
# Install override
database:
host: "customer-db.example.com"
# Final merged result
database:
host: "customer-db.example.com" # Overridden
port: 5432 # From product
ssl: true # From product
```
Arrays are replaced entirely rather than merged:
```yaml theme={null}
# Product inputs
features:
- "basic"
- "standard"
# Install override
features:
- "basic"
- "premium"
# Final merged result
features:
- "basic" # Completely replaced
- "premium" # Not merged
```
When customizing inputs, you only need to specify the keys you want to override. All other product inputs are automatically included in the merged configuration.
## Version management and rollouts
When you update product inputs, Akua records a new product version without affecting existing installations. This gives you precise control over when and how updates roll out to your customers.
### The update workflow
```mermaid theme={null}
flowchart TB
A[Update product inputs] --> B[New package version]
B --> C{Choose rollout strategy}
C -->|Single install| D[Update one installation]
C -->|Bulk update| E[Update all installations]
D --> F[Installation updated]
E --> F
```
### Viewing available updates
Each product installation shows its current package version and whether updates are available:
* **Current version badge** - Shows the package version currently deployed
* **Latest version badge** - Shows the newest available version
* **Update available indicator** - Orange badge when install is behind latest
### Rolling out to a single install
To update a specific installation:
1. Navigate to the product's installations list
2. Click **Update** on the installation row
3. Review the change (current version → latest version)
4. Confirm the update
The installation updates to the latest package version immediately. Use this approach for:
* Testing updates with a pilot customer
* Staggered rollouts across customers
* Customer-requested upgrades
* Selective deployment strategies
### Rolling out to all installs
To update all installations at once:
1. Navigate to the product details page
2. Click **Update All Installs** in the installations section
3. Review the update scope (shows count of installations)
4. Confirm the bulk update
All installations update to the latest package version simultaneously. Use this approach for:
* Security patches requiring immediate deployment
* Critical bug fixes
* Coordinated feature releases
* Simplified version management
Bulk updates execute in parallel but you can monitor each installation's progress individually. Failed updates don't block others from completing.
## Editing inputs
### For products
1. Navigate to your product details page
2. Click the **Values** button in the header
3. Configure each source using the tabbed interface:
* Switch between sources using tabs
* Edit in YAML or form view
* Track changes with modification indicators
4. Click **Apply All** to save changes
This generates a new product version. Existing installations continue running the previous version until you choose to update them.
### For product-based installations
1. Navigate to the installation details page (must not be the product owner)
2. Click the **Values** button in the header
3. Configure each source using the tabbed interface
* You'll see merged inputs (product defaults + any existing overrides)
* Changes are stored as install-specific overrides
4. Click **Apply All** to save changes
This creates install overrides that layer on top of product defaults and triggers an immediate redeployment with the merged configuration.
Product owners cannot edit inputs for product-based installations directly (this would affect all customers). They must update the product instead. Only customers (non-owners) can create install-specific overrides.
### For direct installations
1. Navigate to the installation details page
2. Click the **Values** button in the header
3. Configure each source using the tabbed interface
4. Click **Apply All** to save changes
This updates the installation's `inputs.yaml` and triggers an immediate redeployment with the new configuration.
Changes to direct installations and product-based install overrides take effect immediately. Review configurations carefully before applying.
## Status tracking
Akua provides real-time status indicators during input updates:
| Status | Description |
| ---------------- | ----------------------------------------------------------------- |
| **Saving...** | Writing updated inputs to the installation repository |
| **Packaging...** | Rendering the new configuration into the installation's manifests |
| **Deploying...** | Applying changes to your cluster (direct installs only) |
Progress appears on the Values button, allowing you to monitor the update without blocking other work.
## Best practices
### Version control strategy
* **Update products first** - Make package changes before rolling out to installs
* **Test with single install** - Verify configuration with one customer before bulk updates
* **Use semantic versioning** - Akua automatically versions packages; treat major updates carefully
* **Document changes** - Keep notes on what changed in each version
### Multi-source configuration
* **Configure all sources together** - Use the multi-source editor to apply changes atomically
* **Review modifications** - Check the modified sources count before applying
* **Validate YAML syntax** - The editor warns about syntax errors before applying
* **Use form view for structure** - Form view prevents common YAML formatting mistakes
### Rollout management
* **Pilot test updates** - Start with a single installation for new configurations
* **Stagger large rollouts** - Consider updating installations in batches for large products
* **Monitor after updates** - Check installation health after rolling out changes
* **Keep previous versions** - Don't delete old package versions until all installs are migrated
### Install overrides
* **Minimize overrides** - Only override inputs that truly need to be customer-specific
* **Use product defaults** - Set sensible defaults at the product level for common configurations
* **Document overrides** - Keep notes on why specific inputs were overridden for each customer
* **Test product updates** - Verify that product changes merge correctly with install overrides
* **Review periodically** - Check if overrides are still necessary as product defaults evolve
### Security considerations
* **Never commit secrets** - Use environment variables and secret management for sensitive data
* **Review inputs before applying** - Especially when using form view which may expose all fields
* **Limit who can update** - Product inputs affect all customers; restrict access appropriately
* **Audit changes** - Every input change is a commit in the installation repository — use git history to track who changed what and when
## Common scenarios
Update CPU and memory limits to scale applications. For products, update the product inputs and roll out to installations that need more resources. For direct installs, update inputs directly.
Many packages use feature flags in inputs. Enable features at the product level, generate a new version, then selectively update installations as customers opt in.
Use direct installations for environment-specific installs (dev, staging, production). Each can have different inputs while sharing the same base package.
Update database URLs or connection parameters by editing inputs. For products, create a new version with updated defaults. For direct installs, update directly to reconfigure immediately.
Adjust replica counts, autoscaling settings, and resource requests. Test with a single installation first, then roll out to others once validated.
Use per-install input overrides for product-based installations when customers need unique configurations. Navigate to the installation details page and edit inputs to create customer-specific overrides for custom domains, resource limits, feature toggles, or any other settings. These overrides layer on top of product defaults and persist across product updates, giving you the benefits of centralized product management while supporting customer-specific customizations.
## Troubleshooting
### Changes not applying
If input changes don't take effect:
* **Check syntax** - Ensure YAML is valid with proper indentation
* **Review status** - Wait for "Packaging..." status to complete
* **Verify rollout** - For products, ensure you've updated the installations
* **Check logs** - View application logs for deployment errors in the installation details page
### Schema validation errors
If the form view shows validation errors:
* **Check required fields** - Some inputs must be provided
* **Verify data types** - Ensure numbers, strings, and booleans match schema
* **Switch to YAML** - Use YAML view for complex configurations
* **Consult package docs** - Review the package's documentation for input requirements
### Installation not updating
If an installation doesn't update after rollout:
* **Review version** - Verify the installation is pointing to the new package version
* **Check status** - Look for errors in the installation details page
* **Check deployment** - Ensure the application is deploying successfully
## Related topics
Create and manage products with configurable inputs.
Install applications on your infrastructure.
How Akua generates packages.
How commit history maps to installs.
# Custom dashboards
Source: https://docs.akua.dev/dashboards/custom-dashboards
Build live monitoring dashboards from reusable code snippets
Custom dashboards let you build live monitoring views for your infrastructure by combining reusable code snippets into a configurable grid layout. Each widget runs a snippet that queries the Akua API and displays the result as a table, stat, JSON tree, or log output.
Snippets use sandboxed JavaScript execution with the same `cnap.request()` API, V8 isolation, and security model used by Akua's automation layer. You can write snippets by hand and preview them before saving.
## How it works
Dashboards are built from two building blocks:
* **Snippets**: JavaScript functions that query the Akua API and return data. Each snippet has a display type (table, stat, JSON, or logs) that controls how the result is rendered.
* **Dashboards**: Grid layouts that arrange snippets as widgets. Each widget can span 1–4 columns and runs its snippet automatically when you open the dashboard.
You write a snippet once, then reuse it across multiple dashboards. When you update a snippet, every dashboard that uses it picks up the change.
## Creating a snippet
Navigate to **Dashboards → Snippets** tab and click **New snippet**.
Snippets are `async` JavaScript functions that use `cnap.request()` to call the [Akua API](/apis/introduction). The workspace header is injected automatically, so you don't need to pass authentication or workspace IDs.
```javascript theme={null}
async () => {
const res = await cnap.request({
method: "GET",
path: "/v1/clusters",
});
if (res.status !== 200) throw new Error(JSON.stringify(res.body));
return res.body.data.map(c => ({
name: c.name,
status: c.kaas?.status ?? "imported",
version: c.kaas?.version ?? "—",
}));
}
```
The editor includes a side-by-side preview. Click **Run** to execute the snippet and see the result before saving.
Use the **Examples** dropdown in the snippet editor to load pre-built snippets for common tasks like listing clusters, counting installs, or generating status reports.
### Display types
The display type controls how the snippet result is rendered in dashboard widgets:
| Display type | Return value | Use case |
| ------------ | ----------------------- | --------------------------- |
| **Table** | Array of objects | List resources with columns |
| **Stat** | Single number or string | KPIs, counts, status values |
| **JSON** | Any object | Structured data, breakdowns |
| **Logs** | String | Text reports, log output |
### The `cnap.request()` API
Snippets run in a sandboxed environment with access to a single function:
```javascript theme={null}
const response = await cnap.request({
method: "GET" | "POST" | "PUT" | "DELETE",
path: "/v1/...",
body: { ... }, // optional, for POST/PUT
});
// response.status — HTTP status code
// response.body — parsed JSON response
```
All requests are authenticated and scoped to the current workspace. See the [API reference](/apis/introduction) for available endpoints.
Snippets execute server-side in an isolated sandbox. They cannot access `require`, `process`, `fs`, or any Node.js APIs; only `cnap.request()` is available.
## Creating a dashboard
Navigate to **Dashboards** tab and click **New dashboard**. Give it a name and optional description, then click **Create dashboard** to open the builder.
### The dashboard builder
Dashboards open in **view mode** by default, showing your widgets in a live grid. Click **Edit** to enter edit mode, where overlay controls appear on each widget:
* **Move up/down**: reorder widgets in the grid
* **Resize (−/+)**: adjust column span from 1/4 to full width
* **Edit snippet**: jump to the snippet editor
* **Delete**: remove the widget
Use the **Add widget** bar at the bottom to select a snippet and add it to the dashboard. Click **Save** when you're done, or **Done** to return to view mode.
Use **Cmd+S** (Mac) or **Ctrl+S** (Windows/Linux) to save without clicking the button.
## Workspace scoping
Snippets and dashboards follow the same workspace scoping as other Akua resources:
* **When a workspace is selected**: you see snippets and dashboards belonging to that workspace.
* **When "All workspaces" is selected**: you see snippets and dashboards from all workspaces you have access to.
Snippet API calls are always scoped to the workspace the snippet belongs to.
## API
Manage snippets and dashboards programmatically.
Create, update, run, and delete snippets.
Create dashboards and manage their widget layout.
## Related topics
API endpoints for snippets and beyond.
How workspaces organize resources.
# Delivery
Source: https://docs.akua.dev/delivery
Package applications, deliver installations, and manage customer install changes
Delivery is how Akua turns software into running installations. You define a Product, connect a Package version, and Akua handles installation, configuration, version tracking, and customer-specific install changes.
Use this section when you want to package software for yourself, publish software for customers, or keep installed products updated through reviewable repository changes.
Understand running instances, lifecycle states, and installation ownership.
Check status, inspect logs, review changes, and roll back.
Create the installable package Akua deploys to clusters.
Prepare, review, and accept install changes before they apply.
## Common paths
* Start with [Installations](/installs) to understand the runtime model.
* Use [Operate an installation](/installs/operations) when you need status, logs, rollbacks, or reviewed changes.
* Use [Package authoring](/packages) when you are preparing software for deployment.
* Read [Installation repositories](/installs/repositories) when you need the git-backed source-of-truth model.
# Welcome to Akua
Source: https://docs.akua.dev/index
Get started with Akua - connect agents, deploy applications, manage infrastructure, and sell cloud-native software
Akua is the cloud-native application platform for agents and teams. Connect an agent, deploy applications, manage infrastructure, and sell your software from one workspace.
## Choose your path
## Quick links
Most users start with the [Quickstart](/quickstart) to connect an agent, then ask that agent to prepare compute, package software, or create a Product.
# Installations
Source: https://docs.akua.dev/installs
Install, version-control, and customize applications on your clusters
Installations cover how applications land on your clusters: the per-installation git repositories that make every install auditable, the inputs editor, and the package model that ties it all together.
Every installation gets its own private git repository, whether a customer purchased your product or you installed a tool directly. That repository is the source of truth for the install: the customer's wizard inputs, the composition logic, and the rendered Kubernetes resources your cluster applies.
The git-backed model behind every installation: what it stores and how to use it.
Author package.k, inputs, dependencies, and UI metadata.
Wizard editor, per-install overrides, and staged rollouts.
Check health, stream logs, review changes, and roll back.
Versioned install definitions and input schemas.
How commit history maps to installations and how to roll back.
## Two ways to install
### Product-based installations
Product-based installations are created when customers purchase through the marketplace or an Offer, or when you install a Product manually from your dashboard. Each installation is customer-scoped and points back to the Product and Package version that created it.
Use product-based installations when you are selling software to customers, need marketplace distribution, or want customer installs to inherit product defaults.
### Direct installations
Direct installations let you install applications without a Product or Offer. They are ideal for supporting systems (shared databases, monitoring stacks, API gateways) that your products depend on but that are not sold individually.
Use direct installations when you are setting up infrastructure, internal tools, or services that do not need per-customer billing.
Both installation types follow the same underlying model: a Package version is selected, an installation repository is provisioned, the cluster syncs the rendered manifests, and Akua monitors the [installation lifecycle](/installs/lifecycle).
Direct installations do not point back to a Product. In API responses, `product_id` is present only for product-based installations; every installation still includes its selected Package version.
Most sensitive edits land through [repository change requests](/installs/repository-change-requests): an agent's fix, a partner's update, an automated version bump, or any change that needs review before it reaches the installation. Routine dashboard edits and accepted change requests both resolve to the same repository-backed lifecycle.
## API
Create product-based installations or direct installations, read their live status, and stream logs over the REST API. Per-endpoint parameters and response shapes live in the auto-generated reference.
Create, read, and delete installations and inspect their lifecycle.
States, renders, status, pods, and logs for a live install.
The git repository behind every installation.
Mint API tokens for programmatic access.
## Related topics
Turn Packages into sellable catalog items.
Set up infrastructure for your installations.
How customers start guided installs from private offer links.
The open-source substrate behind every Akua installation.
# Package generation
Source: https://docs.akua.dev/installs/chart-generation
How Akua turns your product configuration into a per-install repository
When a customer installs your product, Akua generates a self-contained repository for that specific installation. The repository combines your product's source, the customer's wizard inputs, and the rendered Kubernetes resources. It is the install target: your cluster reads from it, your team can edit it, and every change ships with a commit history.
This is different from a one-time chart build. Each installation has its own repository and evolves independently as customers configure their installs.
## What gets generated
For every installation, Akua creates a private git repository with this layout:
| Path | Contents | Editable? |
| ------------- | ---------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| `package.k` | Composition logic that turns inputs into Kubernetes resources, applies install-scoped labels, and can patch any field. | Yes (advanced) |
| `inputs.yaml` | The wizard values your customer set. Re-rendering reads from here. | Yes (everyday changes) |
| `upstream/` | A pinned copy of the product's source package, the same version used to render every install of this product. | Rare (version pinning) |
| `manifests/` | The rendered Kubernetes resources. Your cluster pulls from here. | Never (regenerated) |
| `akua.toml` | Package metadata: name, version, dependencies. | Rare |
When inputs change through the dashboard wizard, the API, or an accepted repository change request, Akua re-renders `manifests/` and commits the result. Your cluster picks up the new commit and converges.
## Self-contained by design
The repository vendors its upstream source under `upstream/`. This means:
* **Reproducible.** Re-rendering the same `inputs.yaml` against the same `upstream/` always produces identical manifests.
* **Offline-capable.** No external fetches happen during install rendering. Whatever the upstream looked like at provision time is what ships.
* **Audit-friendly.** Every byte that ends up in your cluster is committed and signed.
If the upstream source disappears tomorrow, your installations keep working. You can update the pin on your own schedule.
## When packages are generated
| Event | What happens |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| New installation | A new repository is created, the upstream is vendored, the wizard inputs are written, and the first render is committed. |
| Wizard edit | `inputs.yaml` is updated, manifests are re-rendered, and a new commit is pushed. |
| Accepted repository change | Reviewed edits to `package.k` or `inputs.yaml` trigger a re-render on the same repository. |
| Upstream version bump | Update `akua.toml`'s upstream pin and re-vendor; the next render uses the new version. |
The render is idempotent: if your edit produces byte-identical manifests, no commit is made and no rollout is triggered.
## Why per-install repositories
A product might have hundreds of installations, each with its own configuration, version pinning, and ad-hoc tweaks. The per-install repository model means:
* **Customer A** can pin to last month's upstream while **Customer B** runs the latest, with no special handling on your side.
* A patch you make for **Customer A** stays scoped to their repository, with no risk of affecting other customers.
* Each customer's installation history is a normal git log they can audit, branch, or roll back independently.
You don't manage this complexity manually. Akua generates the right repository for each installation; you only intervene when you want to.
## Working with the generated package
Most of the time you don't touch it directly. The dashboard wizard handles inputs, and Akua handles rendering. For the cases where the UI doesn't expose what you need:
* **Edit inputs in YAML**: clone the repository, edit `inputs.yaml`, and send the change through the normal review path. Akua re-renders and rolls out after the change is accepted.
* **Patch resources**: edit `package.k` to add or modify fields on rendered resources.
* **Add resources**: append to the `_extras` list in `package.k` to ship resources the upstream doesn't include.
* **Roll back**: prepare a `git revert` and send it through the normal review path.
See the [Customize an installation via git](/installs/install-repo) guide for end-to-end examples.
## Related topics
Edit inputs, patch resources, and use review paths.
How commit history maps to installations.
Multi-source values editor and overrides.
Author package.k, inputs, dependencies, and UI metadata.
# Customize an installation via git
Source: https://docs.akua.dev/installs/install-repo
Understand the git repository behind an installation: change inputs, override resources, and roll out reviewed updates
Every installation you create on Akua gets its own private git repository. Cloning it gives you version-controlled access to the install configuration: the inputs your customer set in the wizard, the rendered Kubernetes resources, and the upstream package source. A repository change becomes live after it passes through the install's normal review and render path.
Most customers never need to touch this. The dashboard wizard and the values editor cover the common cases. The git repository is the escape hatch for the moments where you need to do something the UI doesn't expose: patch a resource, add a sidecar, swap an image registry, or pin a version.
This page covers what to edit and how those edits affect the install. When a change should be reviewed before it lands — an agent's fix, a partner's update, or an automated bump — prepare it through a [repository change request](/installs/repository-change-requests).
## Find your installation's repository
Open your installation in the dashboard. The **Source** tab shows the clone URL and the latest applied commit.
```bash theme={null}
# The URL has the form https://git.akua.dev//.git
git clone https://git.akua.dev/your-org/your-install-id.git
cd your-install-id
```
The repository requires authentication. Your dashboard token works as the password; use any string for the username.
The repository is private and isolated to your workspace. Only authorized workspace members can clone it or submit changes.
## What's inside the repository
You'll edit `inputs.yaml` (the wizard values) for everyday changes and `package.k` (composition logic) for advanced ones. `manifests/` is rendered output; never edit it. `akua.toml` and the vendored `upstream/` copy round out the layout. For the full file-by-file breakdown and who owns each file, see [Installation repositories](/installs/repositories#whats-in-the-repository).
## Common edits
### Change a value
Edit `inputs.yaml`, commit, and send the change through your normal review path.
```bash theme={null}
# Bump the replica count
$EDITOR inputs.yaml
git commit -am "scale replicas to 5"
```
After the change is accepted, Akua re-renders `manifests/` from the new inputs and rolls out the change to your cluster. The installation status updates as the cluster converges.
### Override a single field on a rendered resource
When `inputs.yaml` doesn't expose what you need, edit `package.k`. The composition layer lets you patch any field on any resource without forking the upstream package.
```python theme={null}
# package.k — example: add a node selector to every Deployment
_patched = [r | {
if r.kind == "Deployment":
spec.template.spec.nodeSelector: { "node-pool": "high-memory" }
} for r in _upstream]
```
Commit the patch and send it through your normal review path. The change rolls out after it is accepted.
### Add a resource the upstream doesn't include
Append it to the `_extras` list in `package.k`:
```python theme={null}
_extras = [
{
apiVersion: "v1"
kind: "ConfigMap"
metadata.name: input.appName + "-feature-flags"
data: { enableNewUI: "true" }
}
]
```
The new resource ships alongside the upstream's resources after the change is accepted and rendered.
## Updating from upstream
When the upstream package publishes a new version, you can pull it into your installation without losing your edits:
Edit `akua.toml` to point at the new upstream version.
Run `akua vendor` to refresh the `upstream/` directory.
Your edits in `package.k` and `inputs.yaml` carry over. The upstream change merges into `manifests/` on the next render.
## Rollbacks
The repository is a normal git history. Roll back by reverting:
```bash theme={null}
# Roll back to the previous applied commit
git revert HEAD
```
Send the revert through the same review path you use for other installation changes. Akua re-renders after the rollback is accepted, and the cluster converges to the reverted state.
## What Akua overwrites
`manifests/` is regenerated whenever Akua accepts and renders a repository change; never edit it by hand. `inputs.yaml` can be rewritten when a customer changes wizard values from the dashboard, so put changes that must survive customer edits in `package.k`. `package.k`, `akua.toml`, and `upstream/` are never overwritten. See [how the repository stays in sync](/installs/repositories#how-it-stays-in-sync-with-the-dashboard) for the full model.
## Related topics
Multi-source values editor and per-install overrides.
The model behind the per-install git repository.
How commit history maps to installations.
Sellable install configurations.
# Installation lifecycle
Source: https://docs.akua.dev/installs/lifecycle
The Installation as a living resource: create, render, observe status, pods, and logs, then delete
An installation is a living resource, not a one-shot deploy. Once you create one, Akua keeps it converging toward the state in its [repository](/installs/repositories) and exposes that work as something you can observe: a current state, a render history, the pods running on your cluster, and a live log stream. This page covers that lifecycle end to end.
"Installation" is the unit. It is distinct from a Kubernetes Deployment, which is one of the resource kinds an installation might render. The wire ID is `inst_…` and the API tag is `Installs`.
## The lifecycle states
Every installation reports a single lifecycle state. It moves through the states below as Akua renders the package, syncs the result to your cluster, and watches the running resources.
```mermaid theme={null}
flowchart TB
pending([pending]) --> rendering([rendering])
rendering --> syncing([syncing])
syncing --> healthy([healthy])
healthy --> degraded([degraded])
degraded --> healthy
rendering -.-> failed([failed])
syncing -.-> failed
healthy -.->|delete| deleted([deleted])
```
* **pending**: the installation exists; work has not started yet.
* **rendering**: Akua is turning the package and its inputs into Kubernetes manifests.
* **syncing**: the rendered manifests are being applied to your cluster.
* **healthy**: every resource reports healthy and the cluster matches the repository.
* **degraded**: the installation is live but one or more resources are unhealthy or still settling.
* **failed**: a render or sync could not complete. The status carries the reason.
* **deleted**: the installation has been torn down.
A `healthy` installation is not frozen. When inputs change or upstream resources drift, it re-renders and re-syncs, passing back through `rendering` and `syncing` before returning to `healthy`. A status flag tells you when this reconciliation is in flight.
## Create an installation
You create an installation in one of two ways, both covered on the [Installations overview](/installs#two-ways-to-install): a **product-based** install (from a marketplace purchase, an Offer, or a manual product install) or a **direct** install (an application you run without a Product). Both resolve to the same resource and the same lifecycle.
Creating an installation provisions its [repository](/installs/repositories), records the chosen package version and any initial inputs, and starts the first render. From there it follows the states above on its own; you do not drive each step by hand.
## Renders and render history
A **render** is one attempt to turn the installation's package, inputs, and vendored upstream into the manifests your cluster applies. Renders are the audit trail of how the installation reached its current shape.
* Akua renders automatically whenever the inputs or composition change.
* You can also request a render explicitly, for example to retry after fixing a failed input or to attach a message to the attempt.
* Renders are content-addressed. If a render produces manifests identical to the last one, Akua records no new revision and triggers no rollout, so equivalent edits never churn your cluster.
Each render is kept as an artifact with its own ID, so the **render history** lets you see what was produced, when, and whether it changed the installation. This is the same content-hashing model described in [package versioning](/installs/versioning), viewed from the render side rather than the commit side.
## Read the status
The installation status is the single place to answer "is this install healthy right now." It reports:
* **Health**: whether the running resources are healthy, degraded, or still progressing.
* **Sync**: whether the cluster matches the repository or has pending changes to apply.
* **Revision**: the deployed revision the cluster is currently converged to.
* **Per-resource health**: the kind, name, and health of each rendered resource, so you can find the one workload holding the install in `degraded`.
* **Reconciling**: whether a render or sync is in flight, so a transient `degraded` is not mistaken for a stuck one.
Use the status for dashboards and automated health checks. It is the read model behind the state badge in the dashboard.
## Inspect pods and stream logs
When you need to look past the rolled-up status into the running workload, two surfaces drop you to the pod level:
* **Pods**: the current pod names and their containers for the installation. This is how you find which pod to inspect when a resource reports unhealthy.
* **Logs**: a live log stream for the installation. Stream all pods at once, or pass a single pod name to follow just that one. This is the fastest path from "the install is degraded" to the line that explains why.
Both read directly from the cluster the installation runs on, so they reflect the live workload rather than the last render.
## Delete an installation
Deleting an installation tears down the resources it created on your cluster and moves the installation to `deleted`. The teardown runs in the background and is safe to retry: a repeated delete on an installation already being removed converges on the same end state rather than erroring.
Deletion is scoped to the one installation. Other installations of the same product, each with its own repository and lifecycle, are untouched.
## API
Drive the full lifecycle over the REST API. Per-endpoint parameters, response shapes, and a try-it playground live in the auto-generated reference.
Create, read, and delete installations and list their renders.
Live health, sync, revision, and per-resource state.
Start a render attempt and record the resulting artifact.
Follow live logs for the installation or a single pod.
## Related topics
Check status, logs, changes, and rollback paths.
The git-backed source of truth every installation renders from.
How renders map to commits and how to roll back.
Reachable hostnames bound to an installation.
# Operate an installation
Source: https://docs.akua.dev/installs/operations
Check health, inspect logs, review changes, and roll back an Akua installation
An installation keeps running after the first deploy. This page is for operators who need to answer four questions quickly: what is running, is it healthy, what changed, and how do we safely change it again?
Use the dashboard for the common path, or use the API when you need automation. The same underlying installation model powers both.
## Start with status
The installation status is the fastest way to tell whether the cluster matches the installation repository.
Check:
* **State**: whether the installation is `pending`, `rendering`, `syncing`, `healthy`, `degraded`, `failed`, or `deleted`.
* **Health**: whether rendered resources are healthy or still settling.
* **Sync**: whether the cluster is converged to the latest accepted repository revision.
* **Revision**: the commit SHA the cluster is currently running.
* **Reconciling**: whether Akua is actively rendering or applying a change.
For the full state model, see [Installation lifecycle](/installs/lifecycle).
## Inspect pods and logs
When status says an installation is degraded, inspect the live workload:
* Use **Pods** to see the current pods and containers for the installation.
* Use **Logs** to stream output from all pods, or narrow the stream to one pod when the failing workload is obvious.
Logs come from the running installation. They can include whatever your application writes to stdout or stderr, so avoid logging secrets or customer data.
## Review what changed
Every installation has a private git-backed repository. That repository stores the package definition, inputs, vendored source, and rendered manifests that explain what the cluster is trying to run.
Use the repository history when you need to compare two rollouts, audit a customer-specific change, or understand why a render produced different manifests. See [Installation repositories](/installs/repositories) and [Package versioning](/installs/versioning).
## Make changes safely
Sensitive changes should go through a [repository change request](/installs/repository-change-requests). A change request prepares edits in a managed fork, validates them, and applies them only after an authorized reviewer accepts the proposal.
Use change requests for:
* Agent-authored fixes.
* Partner or CI-authored updates.
* Customer-specific patches that need approval before rollout.
* Automated version or image updates that should be reviewed first.
After a change request is accepted, Akua applies the change, records the new repository revision, and the installation moves through the normal render and sync lifecycle.
## Roll back
Rollback is git-history-backed: restore the installation to a previous known-good repository state, then let Akua render and sync that state to the cluster.
For reviewed environments, prepare the rollback as a repository change request so the revert is validated and approved before it reaches the installation. The resulting commit stays in history, so the original change and the rollback are both auditable.
## API
Operate installations programmatically.
Read health, sync, revision, and resource state.
Follow live logs for an installation or pod.
Propose, review, accept, reject, and withdraw changes.
Inspect render attempts and artifacts.
## Related topics
Lifecycle states, renders, pods, and logs.
Review proposed changes before they apply.
Compare revisions and understand rollback history.
The git-backed source of truth for each install.
# Installation repositories
Source: https://docs.akua.dev/installs/repositories
The git-backed model behind every Akua installation: what it stores, why it works this way, and how to use it
Every installation on Akua lives in its own private git repository. The repository is the source of truth for the install: your customer's wizard inputs, the composition logic that turns those inputs into Kubernetes resources, and the rendered manifests your cluster actually applies. Dashboard edits, accepted change requests, and approved automation all become repository changes that Akua renders and syncs to the cluster.
This page explains the model. For reviewed changes, see [Repository change requests](/installs/repository-change-requests). For the operator checklist, see [Operate an installation](/installs/operations).
## Why per-installation
A product on Akua can have hundreds of installations. Each one belongs to a different customer, runs in a different cluster, may pin to a different upstream version, and may carry its own ad-hoc tweaks. The per-installation repository keeps these isolated:
* **Customer A** can edit their installation's `inputs.yaml` without touching anyone else's install.
* A patch you make for **Customer B** stays scoped to their repository.
* Each installation's history is a normal git log (branchable, diffable, revertible), independent of every other install.
The alternative (one shared repository, many directories) would make customer isolation a feature you'd have to enforce. With separate repositories, isolation is the default.
## What's in the repository
```text theme={null}
your-install-id/
├── akua.toml # Package metadata: name, version, dependencies
├── package.k # Composition logic — turns inputs into resources
├── inputs.yaml # The wizard values your customer set
├── upstream/ # Pinned vendored copy of the source package
└── manifests/ # Rendered Kubernetes resources (Akua applies these to your cluster)
```
| File or directory | Owner | Purpose |
| ----------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `akua.toml` | You | Package identity. Mostly stable; edited when bumping the upstream pin. |
| `package.k` | You | The composition layer. Adds install-scoped labels, can patch any field on any rendered resource, can append extra resources the upstream doesn't include. |
| `inputs.yaml` | Customer + you | The wizard's output. Editable from the dashboard wizard, the API, or directly via git. |
| `upstream/` | Akua | A pinned snapshot of the product's source. Vendored at provision time so renders are deterministic and offline-capable. |
| `manifests/` | Akua (rendered) | Output of `package.k` + `inputs.yaml` against `upstream/`. Regenerated on every change; never edit manually. |
## How it stays in sync with the dashboard
The repository and the dashboard are not two separate stores. They are two views over the same content. The dashboard wizard reads `inputs.yaml`; saving a wizard change writes a commit. Reviewed repository changes update the dashboard view too, and a reviewed revert rolls it back.
In reviewed environments, prepare changes through a [repository change request](/installs/repository-change-requests) so Akua can validate and apply them through the approval path. Either way, the result is a repository commit that the dashboard and cluster both see.
* A customer changes a value through the wizard: commit lands and appears in history.
* A change request is accepted: Akua merges the fork and starts the normal render lifecycle.
* Automation edits an install through an approved path: the repository history records the change.
The dashboard owns `inputs.yaml`: if a customer saves a wizard change while you are preparing a repository change, review the latest inputs before submitting your proposal. Use `package.k` for changes that must survive customer-driven wizard updates.
## Rendering: pure, idempotent, offline
The render step turns `package.k` + `inputs.yaml` + `upstream/` into `manifests/`. It has three properties worth understanding:
1. **Pure.** Identical inputs always produce identical manifests, byte-for-byte. There's no clock, no network, no secret material in the render context.
2. **Idempotent.** Akua hashes the rendered manifests; if a render produces the same hash as the previous one, no commit is made and no rollout is triggered. Whitespace edits to `inputs.yaml` don't churn history.
3. **Offline-capable.** Because `upstream/` is vendored, renders work without any external fetches. If the original source package becomes unavailable, your installations keep working.
Together these mean: re-running a render against the same commit always produces a no-op, and the install your cluster syncs to is fully reproducible from the repository alone.
## Where the repository lives
Akua-managed installations are hosted at `git.akua.dev//.git`. Repositories are private and isolated to your workspace. Authenticate with your dashboard token (use any string for the username; the token is the password).
The dashboard's **Source** tab on every installation shows the clone URL, the latest applied commit SHA, and a link into the repository's history. To watch the resulting installation converge, see the [installation lifecycle](/installs/lifecycle): its live state, status, pods, and logs.
## Repositories and the wider package model
The per-installation repository is one slice of Akua's package model. The same `package.k` + inputs concept applies to:
* **Products** (today): the source you publish gets vendored into every installation.
* **Policies** (planned): workspace-wide policy bundles that layer on top of per-install renders.
* **Repository change requests**: agent-authored or human-authored forks of an installation's repo, reviewed and accepted through Akua rather than landed directly. See [Repository change requests](/installs/repository-change-requests).
The repository as a primitive (versioned, isolated, pure to render) is what makes those follow-on capabilities composable.
## Related topics
Understand the repository editing model.
Propose and review changes before they reach production.
How commit history maps to installations and how to roll back.
Endpoints, parameters, and try-it playground.
# Repository change requests
Source: https://docs.akua.dev/installs/repository-change-requests
Review proposed changes to an installation before they reach production: who proposes, who accepts, and how external proposers get a scoped token
A repository change request is a proposed edit to an [installation repository](/installs/repositories) that someone reviews before it takes effect. Instead of writing directly to the installation, a proposer opens a change request against a fork of the repository. The change is validated, surfaced for review, and applied only when an authorized reviewer accepts it.
This is the review gate behind sensitive changes to an installation. Change requests exist for cases where a change should be proposed, validated, and accepted before it reaches the installation: an agent fixing a misconfiguration, a partner preparing an update for a customer's environment, or an automated update that a regulated buyer wants to approve before rollout.
## Why changes are reviewed
The installation repository is the source of truth for what runs on a cluster: the wizard inputs, the composition logic in `package.k`, and the pinned package version. Editing any of those changes the live installation. For some changes you want a deliberate checkpoint before that happens.
Repository change requests give you that checkpoint:
* **Nothing lands without review.** A proposed change sits in a fork until someone accepts it. Until then the installation is untouched.
* **The proposer and the accepter can be different.** An agent or a partner can prepare a change without being able to apply it. Accepting is a separate, grantable permission.
* **Every decision is recorded.** The proposal, its validation result, and the accept, reject, or withdraw decision are kept as a durable record alongside the repository's git history.
This matters most when a change comes from somewhere other than your own keyboard. Agent-authored fixes and partner-pushed updates are proposals by default, so a person stays in control of what reaches production.
## The lifecycle
A change request moves through a small set of states from the moment it opens to the moment it is accepted, rejected, withdrawn, or expires.
```mermaid theme={null}
%%{init: {'flowchart': {'nodeSpacing': 55, 'rankSpacing': 60, 'curve': 'basis'}}}%%
flowchart TB
you["You"] --> open
agent["An agent"] --> open
auto["Automated update"] --> open
open["Change request opened
(awaiting changes)"] --> validate["Validated automatically"]
validate --> ready["Ready for review"]
ready -->|accept| applied["Accepted
applied to the installation repository"]
ready -->|reject| rejected["Rejected
with a reason"]
ready -->|withdraw| withdrawn["Withdrawn
fork removed"]
ready -.->|no decision in time| expired["Expired"]
```
While a change request is open, the proposer pushes work to the fork and Akua validates it. A change request that fails validation surfaces the problem instead of becoming acceptable. A request that no one acts on expires on its own, so stale proposals do not pile up against an installation.
## Who can propose a change
A change request records who created it, so reviewers can weigh the source:
* **You.** Prepare a change for a teammate to review, or stage a change you want recorded before it lands.
* **An automation actor.** When automation needs to change repository-backed source or configuration, a change request is its default path. It attaches evidence to its proposal: a summary, the likely fix, and the resources it inspected. Automation reads existing change requests first to avoid duplicating work already in progress.
* **The platform.** Automated updates, such as a new image tag or a refreshed package version, can arrive as proposals rather than landing silently.
* **An external proposer.** A CI job or a partner's backend can contribute to a managed fork using a scoped token (below).
## The external proposer token
A change request is backed by a fork of the installation repository. To let an external proposer push work to that fork, you mint a short-lived token scoped to the fork alone.
The token grants write access to the fork's git remote and nothing else. It cannot touch the parent installation, other repositories, or anything outside the fork. Tokens are short-lived: they expire within one hour at most, and you choose a shorter window when you need one.
Create the change request against the installation repository you want to change. This provisions the fork that work will be pushed to.
Request a token for the change request. You receive the fork's remote URL, a write token, and an expiry timestamp.
The CI job, agent, or partner pushes its proposed changes to the fork remote using the token. The token's reach is limited to that fork.
Once the proposer has pushed, the change is validated and becomes ready for review. Accept, reject, or withdraw it.
The token is the handoff that lets a proposer who does not own the installation contribute a change safely. The review gate still decides whether that change ever reaches the cluster.
## Reviewing a change: accept, reject, withdraw
A change request that is ready for review has three terminal actions:
* **Accept.** Akua validates the change and applies it to the parent installation repository. Accepting kicks off the apply as a background operation you can follow to completion. Accepting can require its own grant and a separate approval, so being able to read or prepare a change does not imply being able to accept it.
* **Reject.** Decline the change and record a reason. The reason is kept with the change request for the audit record and review history. The installation is unchanged.
* **Withdraw.** Pull back a change request that is still editable. Withdrawing removes the fork. Use this when a proposal is no longer needed or was opened by mistake.
Only an accepted change reaches the installation. Rejecting and withdrawing both leave the installation exactly as it was.
## What happens on accept
When you accept a change request, Akua revalidates the proposed change, merges it into the installation repository, and rolls the result out to the cluster the same way any other repository edit deploys. The accept runs as a background operation, so you can start it and watch the installation converge.
Because the change merges into the installation repository's normal git history, it is versioned, diffable, and revertible like any other commit. If an accepted change turns out to be wrong, you roll it back the same way you would [roll back any installation edit](/installs/install-repo#rollbacks).
## API
Manage repository change requests programmatically: open them, mint fork tokens, and accept, reject, or withdraw them.
Endpoints, parameters, response shapes, and try-it playground.
Mint API tokens for programmatic proposers and reviewers.
## Related topics
The git-backed model a change request proposes against.
Check status, logs, reviewed changes, and rollback paths.
How installs render, sync, expose status, and stream logs.
API tokens and authentication for proposers and reviewers.
# Package versioning
Source: https://docs.akua.dev/installs/versioning
How installation packages track changes and how to roll back installs
Every installation on Akua has its own package repository, and every change to that package is a git commit. Versioning isn't a separate concept: it's the same commit history you already understand. Each commit has a SHA, an author, a timestamp, and a parent. Rolling back restores a previous repository state, usually through a reviewed change request. Comparing versions is `git diff`.
## How versioning works
When Akua renders an installation (for example, after a customer changes a wizard value), it computes a content hash over the rendered manifests. If the hash matches the previous render, no commit is made. If it differs, Akua commits the new manifests and updates the installation to the new SHA.
This means:
* **Every rollout is a commit.** The commit SHA is what your cluster syncs to.
* **Equivalent edits don't churn history.** Changing whitespace in `inputs.yaml` produces no commit if the rendered manifests don't change.
* **Identical inputs always render identically.** The render is a pure function of `package.k` + `inputs.yaml` + the vendored `upstream/`.
The dashboard and API both expose the latest applied SHA on every installation. The dashboard's install detail page links to the commit; the [`GET /v1/repositories/{id}`](/api-reference/repositories/get-repository-details) endpoint returns it as `last_deploy_sha`. Every render that changes the manifests is also kept in the installation's [render history](/installs/lifecycle#renders-and-render-history).
## Track changes
Because the package is a normal git repository, any tool that works with git history works on it:
```bash theme={null}
# What changed in the last rollout?
git log -1 --stat
# What changed since last week?
git log --since='1 week ago' --oneline
# What manifests differ between two rollouts?
git diff -- manifests/
```
You can clone an installation's repository and inspect, diff, or branch it the same way you would any other git repo.
## Rollbacks
Roll back an installation by restoring a previous known-good repository state. In reviewed environments, prepare the rollback as a [repository change request](/installs/repository-change-requests) so the revert is validated and accepted before it reaches the installation.
The underlying git operation is still a revert:
```bash theme={null}
git clone https://git.akua.dev//.git
cd
git revert HEAD
```
After the rollback change is accepted, Akua renders the new commit and converges the cluster to the reverted state. The original commit stays in history: `git revert` adds an inverse commit rather than rewriting the past.
You can also revert by checking out an older commit, generating a fresh commit on top, and sending it through the normal review path. This is useful when reverting through a chain of changes.
## Compare two rollouts
A common operation: "what changed between yesterday's rollout and today's?"
```bash theme={null}
git diff
```
This shows the diff over `package.k`, `inputs.yaml`, and `manifests/` together, covering every change that affected the installation. For just the cluster-visible diff, scope to `manifests/`.
## Pin and update upstream versions
The `upstream/` directory is the pinned product source for this installation. To update:
Edit `akua.toml` to point at the new upstream version.
Run `akua vendor` to refresh the `upstream/` directory.
Commit the refreshed package state and send it through your normal review path. The next render uses the new upstream. Your edits in `package.k` and `inputs.yaml` carry through unchanged.
Different installations can pin to different upstream versions independently. There is no single "current version" of a product; each installation tracks its own.
## Related topics
How Akua generates packages from your sources.
Understand direct repository edits and review paths.
The git-backed model behind every installation.
Endpoints, parameters, and try-it playground.
# Offer channels
Source: https://docs.akua.dev/marketplace/offer-channels
Governed distribution paths that let partners, private audiences, and beta cohorts carry your offers under reviewed commercial terms
Offer channels are a **restricted entitlement**. They are not available self-serve, and there is no public API for them yet. Access is request-only and requires Akua to enable channels for your workspace. To discuss a channel, contact [support@akua.dev](mailto:support@akua.dev).
An offer channel is a governed distribution path. It lets your workspace extend a controlled set of your [offers](/marketplace/offers) to a partner organization, a private audience, or a beta cohort, without handing over your catalog or your billing. The channel decides which products it covers and which commercial terms every offer in it must follow.
Channels exist for the cases a single shareable offer cannot express on its own: a reseller who distributes your products under terms you set, a closed relationship with named customers, or an early-access cohort that should run without charges. Each of those is a channel with its own policy.
## What a channel controls
A channel scopes the relationship before any offer is created:
| Control | What it does |
| ------------------------ | ------------------------------------------------------------------------------- |
| **Product scope** | Covers all of your products, or a selected list. |
| **Partner** | Optionally binds the channel to a specific partner organization. |
| **Commercial authority** | Sets whether the platform resolves the commercial terms or your workspace does. |
| **Active policy** | Points at the one channel policy version currently in force. |
The channel is the durable relationship. The terms that govern it live in its channel policy.
## Channel policy: the gate every offer passes
Each channel carries a channel policy, a versioned set of rules every offer in the channel must satisfy before it can reach a customer:
* **Pricing bounds.** A default price with a minimum and maximum, in a fixed currency and billing interval. An offer in the channel can set its own price only within these bounds.
* **Commercial mode.** Whether the channel settles real paid charges, runs in non-billable test mode, or allows both.
* **Approval.** Whether paid offers (and test offers) go live automatically or require Akua approval first.
* **Support visibility.** What the partner can see about a customer's installation, such as install state and app URLs. This defines the scoped support relationship between the partner and the customer.
The three gates in the hero above are three policies: an approval gate that holds a partner's paid offers for review, price bounds that cap what a private channel can charge, and a no-charge test mode for a beta cohort.
## Policies are reviewed before they take effect
A channel policy is reviewed before it governs anything. It is drafted, approved, then activated, and only the active version applies to new offers. When you replace a policy, the previous version is archived and the new one takes its place. Nothing in a channel changes its terms without passing through that review.
This is the same reviewed-proposal principle Akua applies elsewhere: a proposed change is validated and approved before it has any customer-visible effect.
## How channels relate to offers
When an offer is created inside a channel, the channel's active policy resolves that offer's commercial terms before it goes live:
* The **commercial mode** (paid or non-billable test).
* Whether **checkout** and payment are required.
* Whether the offer needs **approval** first.
* The **effective price**, drawn from the policy default or the offer's own request, always within the policy's bounds.
* The **support scope** the partner is granted for resulting installations.
If anything blocks the offer (a price outside the bounds, an approval still pending), the resolved terms say so before the offer reaches a customer. One channel can carry many offers this way, all held to the same reviewed terms. Everything downstream of the offer, including the [order flow](/marketplace/order-drafts) and paid checkout when enabled, works exactly as it does for a standalone offer.
## Availability
Offer channels are gated behind a restricted entitlement and are enabled per workspace by Akua. There is no self-serve setup and no public API surface for channels or channel policies today. If your workspace needs partner, private, or beta distribution under governed terms, contact [support@akua.dev](mailto:support@akua.dev) to request access and work through the channel and policy setup together.
## Related topics
Shareable install links with selected inputs and access rules.
The customer flow that begins after someone opens an offer.
Configure the sellable products distributed by offers.
The sellable wrappers a channel distributes.
# Offers
Source: https://docs.akua.dev/marketplace/offers
Short customer URLs with selected inputs, access rules, and checkout flow
An Offer is a shareable URL (`akua.dev/i/`) that sends a customer into the generated install wizard for a Product or Package version. The wizard is rendered from the pinned Package version's input schema, so customers configure their install without a custom form.
## The flow
```mermaid theme={null}
flowchart TB
PKG["Package version
Input schema + @ui annotations"]
PRODUCT["Product
catalog metadata"]
OFFER["Offer
short hash + access rules"]
ORDER["Order draft
customer workspace + configuration"]
CHECKOUT["Checkout
optional payment"]
INSTALL["Installation
running in a workspace"]
PKG --> PRODUCT
PKG --> OFFER
PRODUCT --> OFFER
OFFER --> ORDER
ORDER --> CHECKOUT
CHECKOUT --> INSTALL
```
The customer opens the Offer, signs in if required, chooses or creates a workspace, fills the generated form, completes checkout when payment is required, and receives an installation. Each redemption is tracked as an [order draft](/marketplace/order-drafts) that moves through those states one at a time.
## What an Offer controls
| Control | What it does |
| ---------------------- | ----------------------------------------------------------------------------- |
| **Target and version** | Selects the Product or Package version used by the wizard |
| **Field values** | Pre-fills Package inputs and can lock fields the customer should not change |
| **Access** | Restricts redemption by email, expiry, maximum uses, or private customer flow |
| **Commercial terms** | Selects the payment or private-sale path allowed for this customer |
| **Support visibility** | Lets the seller understand where the customer is in the order flow |
Sensitive values are handled as write-only configuration. Saved offers should show that a value exists, not reveal secret material.
## Generated fields
Each Package input becomes a wizard field. Akua uses:
* KCL docstrings as help text.
* `@ui(order=...)` to sort fields.
* `@ui(group=...)` to group related fields.
* `@ui(widget=...)` for controls such as sliders, password fields, text areas, and selects.
* `@ui(placeholder=...)`, `@ui(min=...)`, and `@ui(max=...)` for form hints and bounds.
See [Package format](/akua/package-format#ui-annotations) for authoring details.
## Public catalog vs private offer
| Path | Use when |
| ----------------------- | --------------------------------------------------------------------------- |
| **Marketplace listing** | Customers should discover the Product publicly and start from the catalog. |
| **Reusable Offer** | You want a shareable campaign or partner URL with a specific configuration. |
| **Private Offer** | You want per-customer terms, email restrictions, expiry, or locked inputs. |
All paths create the same kind of [order draft](/marketplace/order-drafts) and installation. The difference is how much context the seller chooses before the customer starts.
To distribute offers through a partner, a private audience, or a beta cohort under reviewed pricing and approval terms, group them behind an [Offer channel](/marketplace/offer-channels). Channels are a restricted, request-only entitlement enabled per workspace by Akua.
## API
Create, inspect, archive, unarchive, and resolve offers.
Track customer configuration, workspace selection, checkout, and install progress.
Fetch Package versions and input schemas used by generated forms.
Set up API tokens for seller-side automation.
## Related topics
Track the customer flow started by an offer.
Sellable wrappers around Package versions.
Versioned install definitions and input schemas.
Configure commercial terms on the product an offer distributes.
# Order drafts
Source: https://docs.akua.dev/marketplace/order-drafts
The state machine a customer moves through from opening an offer to a live installation
An order draft is the working record of one customer's journey from opening an [Offer](/marketplace/offers) to starting a running [installation](/installs). It is created the moment a customer opens an offer link, and it carries every choice they make along the way: who they are, which workspace receives the install, the inputs they configure, and whether payment is required. The draft advances through a fixed sequence of states, and it is the main thing both the customer's install wizard and your seller dashboard read to know where the customer is right now.
Most customers never see the term "order draft"; they just walk through the guided wizard. As a seller, the draft is how you watch that walk: a draft sitting in `configure` for a long time is a customer stuck on a form, and a draft in `payment` is one who reached checkout but has not paid yet.
## The customer flow
```mermaid theme={null}
%%{init: {'flowchart': {'nodeSpacing': 55, 'rankSpacing': 60, 'curve': 'basis'}}}%%
flowchart TB
OFFER["Customer opens an Offer"]
CLAIM["Claim — sign in and bind the draft"]
WS["Select or create a workspace"]
COMPUTE["Allocate compute"]
BOOT{"New cluster needs
a worker?"}
JOIN["Join a worker node"]
CONFIG["Configure the install"]
PAY{"Payment
required?"}
CHECKOUT["Complete checkout"]
INSTALL["Create the installation"]
LIVE["Installation live"]
ENDED["Cancelled or ended"]
OFFER --> CLAIM --> WS --> COMPUTE --> BOOT
BOOT -->|yes| JOIN --> CONFIG
BOOT -->|no| CONFIG
CONFIG --> PAY
PAY -->|yes| CHECKOUT --> INSTALL
PAY -->|no| INSTALL
INSTALL --> LIVE
CLAIM -.-> ENDED
WS -.-> ENDED
CONFIG -.-> ENDED
```
The branches matter: the worker-join step only appears when the chosen destination is a brand-new managed cluster with no worker yet, and the checkout step only appears when the offer's commercial terms require payment. A free or private offer on an existing cluster runs the short path straight from configure to install.
## The states
Each order draft reports a `status` that names its current state. The states run in order, and `done` and the cancelled state are terminal.
| State | What is happening |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Resolve the offer** | The customer opens `akua.dev/i/`. Akua resolves the offer and creates an order draft against it, still anonymous. |
| **Claim** | The customer signs in (or signs up with email verification) and claims the draft with a one-time token, binding it to their account. |
| **Workspace** | The customer picks an existing [workspace](/workspaces) or creates a new one as the install destination. |
| **Compute** | Akua allocates the cluster the installation will run on. |
| **Worker bootstrap** | Only when the destination is a new managed cluster with no worker: the customer adds a [worker node](/clusters/add-workers) using a short-lived join command, and the draft waits until the node is ready. |
| **Configure** | The customer fills the generated install form. Fields come from the Package version's input schema, with any offer pre-fills and locked fields already applied. |
| **Payment** | Only when the offer requires payment: the customer completes a hosted checkout. |
| **Install** | Akua creates the installation, provisions the customer's [private repository](/installs/repositories), and deploys the selected Package version. |
| **Live** | The installation is running and the order is delivered. |
A draft can also be **cancelled** by the customer, or end on its own when the offer expires, a checkout is abandoned past its window, or an install cannot complete. An ended draft is terminal; the customer starts over with a fresh offer redemption.
## Where payment fits
The payment state is a branch, not a fixed step. When an offer carries paid commercial terms, the draft cannot reach the install state until a checkout session is completed and confirmed. Akua opens a Stripe-hosted checkout, and the customer returns to the wizard once payment succeeds. If a checkout fails or is abandoned, the draft stays in the payment state and the customer can start a new checkout session.
When an offer is free or settles outside checkout (a private sale, or a non-billable test offer from an [offer channel](/marketplace/offer-channels)), the draft skips payment entirely and moves straight to install. Paid checkout is enabled for workspaces as the commerce path rolls out.
## Adding a worker when needed
If the customer routes the install to a freshly created managed cluster that has no compute yet, the draft pauses so they can attach one. Akua issues a short-lived bootstrap command and cloud-init that join a [worker node](/clusters/add-workers) to that cluster. Once the node is ready, the draft continues to the configure state. Installs that target an existing cluster with available capacity never see this step.
## What happens after the draft
The order draft is not the whole lifecycle. It owns the purchase and configure flow up to the point where the install can begin. Once payment is complete, or once a no-charge offer skips payment, Akua records the order, starts delivery, and links the draft to the installation it creates.
From that point, the installation becomes the long-lived resource. Use the draft to understand where a buyer is in the purchase flow. Use the [installation lifecycle](/installs/lifecycle) to monitor the running software: render history, health, pods, logs, and deletion.
## Seller visibility
The order draft is the same record behind the offer's support-visibility view. Watching a customer's drafts tells you where each buyer is in the flow and where they drop off, without exposing their secret configuration values. Sensitive inputs are write-only and are never returned to anyone but the customer who entered them. This is how you support a customer mid-purchase: confirm they reached checkout, see that delivery has started, or spot a draft that ended early.
## API
Track and manage customer order drafts and their checkout sessions programmatically.
Inspect, claim, configure, and cancel order drafts through the flow.
Create and read the checkout sessions attached to a paid order draft.
Create and resolve the offers that start an order draft.
Mint API tokens for seller-side automation.
## Related topics
The shareable links that start every order draft.
Configure the sellable product behind an order draft.
Attach a worker node when an install needs new compute.
What the order draft produces once it goes live.
# Networking
Source: https://docs.akua.dev/networking
Routes, gateways, and domains for your applications
Networking covers how your applications become reachable from the internet. Every access method uses standard Gateway API routing on your cluster. The difference is how traffic arrives at your workers and who manages DNS and certificates.
Instant `*.akua.run` URLs for every installation. No DNS, no certificates, no configuration.
Route through Cloudflare's network using your own account. No public IPs required.
Point your DNS at your worker nodes. Full control over routing and TLS.
Automate workspace subdomains, preview hostnames, and custom domains.
## Choosing an approach
| | Preview domains | Cloudflare Tunnel | Direct IP |
| ---------------------- | --------------------------------- | -------------------------------------------- | ------------------------------------- |
| **Public IP required** | No | No | Yes |
| **DNS setup** | Automatic | Automatic (Akua-managed) | You manage A records |
| **TLS** | Automatic | Cloudflare edge | Bring your own |
| **Best for** | Development, demos, quick sharing | Production custom domains without public IPs | Full control, existing infrastructure |
| **Traffic path** | Cloudflare edge → tunnel → app | Cloudflare edge → tunnel → app | DNS → worker node → app |
## How routing works
All three options use Gateway API routing on your cluster. When you expose a hostname, a route is created that matches incoming requests by hostname and forwards them to the correct application. A gateway controller on the cluster detects the route and configures the appropriate gateway (Cloudflare Tunnel, Cilium's built-in envoy proxy, or another compatible controller).
Because routing is defined through standard Kubernetes Gateway API resources, it works with GitOps workflows, authored Packages, chart sources, and `kubectl apply`. Akua's UI is one way to create routes, not the only way.
For Packages that expose web ports through Akua's generated install flow, Akua can automate routing setup: toggle **Expose externally** on a port, enter a hostname, and Akua creates the route for you. Chart sources can also create routes through their own values when the Package exposes those inputs.
## Related topics
Manage preview hostnames, workspace subdomains, and custom domains programmatically.
Deploy applications to your clusters.
Create and manage the clusters your applications run on.
Set up API tokens for programmatic access.
# Cloudflare Tunnel
Source: https://docs.akua.dev/networking/cloudflare-tunnel
Use your own Cloudflare account to route custom domains to your cluster — no public IPs required
Cloudflare Tunnel lets you expose applications on your own custom domains through Cloudflare's network. Unlike [preview domains](/networking/preview-domains) where Akua manages the domain, here you bring your own Cloudflare account and keep control of Cloudflare-level settings such as access policies, WAF rules, caching, and DNS.
Your worker nodes don't need public IP addresses. A cloudflared agent on your cluster establishes an outbound connection to Cloudflare's edge, and Cloudflare routes incoming requests through the tunnel to your applications.
```
Browser → Cloudflare Edge (TLS + DDoS protection) → Tunnel → Your Cluster → App
```
## Why use this
* **No public IPs needed**: `cloudflared` connects outbound from your cluster. No firewall rules, no port forwarding, no exposed nodes.
* **Your domain, your Cloudflare account**: full control over DNS, caching, access policies, WAF rules, and tunnel settings.
* **Cloudflare edge**: TLS termination, DDoS protection, and global edge caching come built-in.
* **Works anywhere**: behind NAT, corporate firewalls, and private networks, as long as the cluster has outbound internet access.
* **Standard routing**: uses standard Kubernetes Gateway API resources, so the same route configuration works whether you're using Cloudflare Tunnel or another gateway.
## How it works
Akua deploys a Gateway API controller to your cluster that bridges Kubernetes routing with Cloudflare Tunnels. When you create a route (either through Akua's UI or a Helm chart), Akua automatically:
1. Creates a Cloudflare Tunnel and deploys the `cloudflared` agent.
2. Publishes the tunnel endpoint metadata for the route.
3. Updates Akua's routing records and the required Cloudflare DNS and certificate state for the hostname.
Routing updates happen within seconds because the public hostname mapping is updated centrally, without requiring the cluster controller to create or delete per-hostname DNS records.
## Setup
From your cluster's detail page, deploy a **Cloudflare Tunnel** gateway. This installs the Gateway API controller and creates the base gateway resource on your cluster.
Add your Cloudflare API token in the Akua dashboard under your cluster's settings. You'll need a token with two permissions:
| Permission | Scope | Why |
| --------------------------- | ------- | ----------------------------------------------------------- |
| **Cloudflare Tunnel: Edit** | Account | Create and manage tunnels |
| **DNS: Edit** | Zone | Manage DNS and hostname verification state for your domains |
Credentials are stored centrally in Akua, not on your cluster. You can rotate or update your token from the dashboard at any time without touching the cluster.
For Packages that expose web ports through Akua's generated install flow, go to the installation's **Settings > Ports**, toggle **Expose externally**, and enter your custom domain (for example, `app.yourdomain.com`).
For chart sources, configure the route hostname through the Package inputs when the Package exposes those values.
The controller detects the new route and publishes the tunnel endpoint. Akua updates the public routing record and Cloudflare state for the hostname.
Open `https://app.yourdomain.com` in your browser. Cloudflare handles TLS automatically, with no certificate setup needed on your side.
## Compared to preview domains
Both preview domains and Cloudflare Tunnel use Cloudflare's network to route traffic to your cluster. The difference is who manages the configuration:
| | Preview domains | Cloudflare Tunnel |
| ----------------------- | ----------------------------- | -------------------------------------------- |
| **Domain** | `*.akua.run` (auto-generated) | Your own domain |
| **Cloudflare account** | Akua's account | Your account |
| **DNS** | Automatic | Automatic (managed centrally by Akua) |
| **TLS** | Automatic | Automatic (Cloudflare edge) |
| **Tunnel config** | Managed by Akua | Managed by Akua with your credentials |
| **Cloudflare settings** | None (fully managed) | Full control (WAF, caching, access policies) |
If you don't need a custom domain or Cloudflare-level configuration, [preview domains](/networking/preview-domains) are the fastest way to get a public URL.
## Under the hood
**Same controller, different credentials.** Cloudflare Tunnel and [preview domains](/networking/preview-domains) share the same Gateway API controller on your cluster. The difference is whose Cloudflare account is used. For preview domains, Akua uses its own account. For custom domains, Akua uses the credentials you provide in the dashboard. The controller publishes tunnel endpoint metadata to Akua; Akua then routes to the right Cloudflare account.
**Akua acts as a proxy.** The controller on your cluster never calls the Cloudflare API directly. Instead, it sends tunnel endpoint updates to Akua's API, and Akua applies the Cloudflare changes using your stored credentials. This means credential rotation happens in the dashboard, with no cluster access needed. It also gives Akua a complete picture of every tunnel and route across all your clusters, which enables reliable cleanup even if a cluster becomes unreachable.
**One tunnel per gateway.** Each gateway resource on your cluster maps to one Cloudflare Tunnel. The controller deploys a `cloudflared` agent that connects to Cloudflare using a scoped tunnel token. Multiple `cloudflared` replicas can connect to the same tunnel for high availability; Cloudflare load-balances across them automatically.
**DNS records are automatic.** When Akua sees a custom hostname that should route through a Cloudflare Tunnel, Akua creates or updates the Cloudflare DNS and certificate state from the platform side. The cluster controller does not own per-hostname DNS records; it owns the tunnel endpoint metadata that lets Akua route the hostname to the correct cluster.
**Platform-managed public routing.** Akua owns the public hostname routing records for preview domains and Akua-managed custom domains. Your cluster remains the source of truth for Kubernetes service routing, while Akua is the source of truth for which public hostname points at which tunnel endpoint.
## API
Manage custom domains and Cloudflare credentials programmatically.
Create, verify, and delete custom domains on a workspace.
Register and rotate Cloudflare API credentials.
## Related topics
Compare all options for exposing applications.
Instant URLs without DNS setup, managed by Akua.
Route directly to worker node IPs.
Automate custom domains and hostname management.
# Direct IP
Source: https://docs.akua.dev/networking/direct-ip
Route traffic directly to your worker nodes using Gateway API and DNS
With direct IP routing, traffic reaches your applications through your worker nodes' public IP addresses. You point your domains at your workers via DNS, and a Gateway API controller on the cluster routes requests to the correct application based on the hostname.
This approach is ideal for **self-hosted clusters** where you manage the nodes and have direct access to their public IPs.
## How it works with Akua-managed clusters
Clusters created through Akua use Cilium as the CNI, which includes a built-in Gateway API controller. Cilium's envoy proxy runs on every worker via host network mode, listening on ports 80 and 443:
```
Client → worker-node-ip:80 → Cilium envoy (host network) → Route match → Service → Pod
```
The envoy proxy checks the `Host` header against all configured routes and forwards matching traffic to the correct application, regardless of which node the app's pod runs on.
## Imported and cloud-hosted clusters
If you import an existing cluster into Akua, the Gateway API controller depends on your Kubernetes setup:
* **Cloud providers** (GKE, EKS, AKS): these typically include their own Gateway API controller backed by cloud load balancers. Traffic goes through the cloud's load balancer rather than directly to worker node IPs, so you don't need to manage A records yourself.
* **Self-hosted with Cilium**: works the same as Akua-managed clusters. Deploy a Cilium Gateway from your cluster's detail page.
* **Other CNIs**: consult the documentation for your CNI or Kubernetes distribution to set up a Gateway API controller. The route configuration workflow stays the same; only the underlying controller and how traffic enters the cluster differs.
## Prerequisites
* A cluster with a Gateway API controller (Cilium Gateway for Akua-managed and self-hosted clusters, or a cloud-provided controller)
* One or more worker nodes with public IP addresses (for direct IP setups)
* A domain you control with access to its DNS settings
## Set up a custom domain
For Packages that expose web ports through Akua's generated install flow, go to the installation's **Settings > Ports** and toggle **Expose externally** on the port you want to make public. Enter your domain (for example, `app.yourdomain.com`) as the hostname.
For chart sources, configure the route hostname through the Package inputs when the Package exposes those values.
The gateway runs on every worker node, so any worker with a public IP can receive traffic. Choose a DNS strategy based on your setup:
Create one A record pointing your domain at the worker's public IP:
| Record type | Name | Value |
| ----------- | -------------------- | ------------------ |
| A | `app.yourdomain.com` | Worker's public IP |
Add an A record for each worker. DNS automatically distributes requests across them:
| Record type | Name | Value |
| ----------- | -------------------- | ------------------ |
| A | `app.yourdomain.com` | Worker 1 public IP |
| A | `app.yourdomain.com` | Worker 2 public IP |
| A | `app.yourdomain.com` | Worker 3 public IP |
Create A records for a base hostname (for example, `workers.eu.yourdomain.com`) pointing to all workers in a region, then CNAME your app domains to it. When you add or remove workers, you only update the base record:
| Record type | Name | Value |
| ----------- | --------------------------- | --------------------------- |
| A | `workers.eu.yourdomain.com` | Worker 1 public IP |
| A | `workers.eu.yourdomain.com` | Worker 2 public IP |
| CNAME | `app.yourdomain.com` | `workers.eu.yourdomain.com` |
DNS propagation can take a few minutes to a few hours depending on your provider and TTL settings.
Once DNS has propagated, open `http://app.yourdomain.com` in your browser. The gateway routes the request to your application based on the hostname.
## Test before DNS propagation
You can verify that gateway routing works correctly before creating DNS records. Use `curl` with an explicit `Host` header to simulate what a browser does after DNS resolves:
```bash theme={null}
curl -H 'Host: app.yourdomain.com' http:///
```
Replace `` with your worker node's public IP and `app.yourdomain.com` with the hostname you configured.
* **If you see your app's response**: the routing is correct. Create the DNS record and you're done.
* **If you get a 404 from envoy**: the hostname doesn't match any route. Double-check that the hostname in your app's port configuration matches exactly what you're passing in the `Host` header.
This works because HTTP routing is based entirely on the `Host` header. The `curl` command sends the same header a browser would send after resolving your domain through DNS. The only difference is you're connecting directly to the server IP instead of going through DNS.
## Troubleshooting
The gateway is running but no route matches the request's `Host` header. Check that:
* The hostname in your app's port configuration matches your domain exactly.
* The port has **Expose externally** toggled on.
* The route was created (check the app's status).
The gateway's envoy proxy isn't running on the worker node. Verify that:
* A Cilium Gateway is deployed to the cluster.
* The gateway pod is running and healthy.
* Host network mode is enabled in the Cilium configuration.
This is normal with Cilium's host network mode. The gateway creates a ClusterIP service (not a LoadBalancer), so the status never reports an external IP. Traffic still flows correctly through the host network envoy proxy.
DNS propagation can take time. While waiting, use the `curl` test above to confirm routing works. If `curl` returns your app, the issue is DNS propagation, not routing.
## Related topics
Compare all options for exposing applications.
Route custom domains without public IPs.
Instant URLs managed by Akua.
Connect compute with public IPs to your cluster.
# Preview domains
Source: https://docs.akua.dev/networking/preview-domains
Get instant *.akua.run URLs for installations with no DNS setup
Every exposed installation port gets a public HTTPS URL on `*.akua.run`, with no DNS records, no certificates, and no configuration. Toggle **Expose externally** on a port and Akua assigns a managed hostname that works with Cloudflare's standard wildcard certificate. For custom domains or more control over routing, Akua also supports [bringing your own Cloudflare Tunnel](/networking/cloudflare-tunnel) or [routing directly to your nodes](/networking/direct-ip).
Other platforms offer preview URLs too (Vercel, Cloudflare Workers, Fly.io), but they run your app on shared infrastructure. Akua preview domains are different: **your app stays on your clusters, on your servers**. Cloudflare only handles the edge routing; traffic flows through a tunnel directly to the workload running on your infrastructure.
## How it works
1. You expose a port on your installation.
2. Akua assigns a managed hostname, for example `frontend-acme.akua.run` or `pr-42-frontend-acme.akua.run`.
3. Your cluster publishes the tunnel endpoint for that app.
4. Cloudflare handles TLS, then Akua routes the request through the selected tunnel to your app.
```
Browser → Cloudflare Edge (TLS) → Tunnel → Your Cluster → App
```
## Why use preview domains
* **Zero setup**: no DNS provider, no certificate authority, no gateway configuration.
* **Instant sharing**: send a link to a teammate or client the moment you deploy.
* **Your infrastructure**: traffic routes to your own cluster, not a shared platform. You keep full control over where your workload runs.
* **Automatic HTTPS**: TLS is terminated at Cloudflare's edge; every URL is secure by default.
## Limitations
Preview domains are fully managed by Akua (the tunnel, the subdomain, and the DNS), which means you don't control the Cloudflare configuration. There are no options for access policies, custom headers, or tunnel-level settings.
For production workloads that need custom domains or fine-grained tunnel configuration, Akua supports [bringing your own Cloudflare Tunnel](/networking/cloudflare-tunnel): you connect your own Cloudflare account and manage the tunnel settings yourself. You can also [point your DNS directly at your worker nodes](/networking/direct-ip) for full control over the routing stack.
## Under the hood
Preview domains use the same Cloudflare Tunnel infrastructure as [custom domain tunnels](/networking/cloudflare-tunnel), but Akua manages the Cloudflare account and credentials on your behalf.
**One tunnel per cluster.** The first time you expose a port with a preview domain, Akua provisions a Cloudflare Tunnel for your cluster and deploys a `cloudflared` agent. Subsequent preview domains on the same cluster reuse the same tunnel; no additional infrastructure is created.
**Akua assigns a managed hostname.** When you expose a port, Akua creates a flat hostname under `akua.run`, such as `frontend-acme.akua.run`. Preview builds use the same shape with a short prefix, such as `pr-42-frontend-acme.akua.run`. Flat hostnames keep managed URLs covered by the standard wildcard certificate; deeper nested names such as `frontend.acme.akua.run` are not used for managed preview domains.
**Routing is Kubernetes-native.** Exposing a port creates a standard Gateway API route on your cluster. A controller watches for these routes and publishes tunnel endpoint metadata back to Akua. Because routing is defined through standard Kubernetes Gateway API resources, it works with GitOps workflows, authored Packages, chart sources, and `kubectl apply`. Akua's UI is one way to create routes, not the only way.
**DNS is managed centrally.** Preview domains share Akua-managed wildcard DNS and edge routing. Akua does not create a DNS record for every installation hostname, so creating and deleting preview URLs stays fast even when a workspace has many installations or short-lived previews.
**Routing records are updated by Akua.** Unlike [custom domain tunnels](/networking/cloudflare-tunnel) where you manage a domain in your own Cloudflare account, managed preview domains route through Akua's edge. When an app is created, updated, or removed, Akua updates the routing record for the hostname and Cloudflare sends future requests to the current tunnel endpoint.
**Credentials never touch your cluster.** Akua's Cloudflare credentials are managed centrally. The controller on your cluster authenticates with Akua's API using a scoped service account token and never holds Cloudflare API keys directly.
## API
Manage preview hostnames programmatically to create preview URLs in CI/CD pipelines or automate cleanup.
Bind, list, and delete preview hostnames for an installation.
Overview of all domain routing resources and authentication.
## Related topics
Compare all options for exposing applications.
Use your own custom domain with Cloudflare.
Route directly to worker IPs instead.
Automate hostname management through the API.
# Packages
Source: https://docs.akua.dev/packages
Versioned install definitions that power products, offers, and direct installs
A Package is the reusable install definition behind an Akua install. It owns the composition logic, dependencies, version history, and input schema that the dashboard, API, and offer wizard use.
Products and Offers build on Packages. A Product is the sellable wrapper customers discover or buy. An Offer is the shareable sales path for a Product or Package version. The Package is the technical contract both of them point at.
## What a Package owns
| Surface | Owned by Package |
| ----------------- | ------------------------------------------------------------------------------------------------------------ |
| **Source** | Authored `package.k`, Package metadata, and supported sources such as chart dependencies or container images |
| **Versions** | Immutable Package versions with provenance and renderable inputs |
| **Input schema** | The customer-facing fields exported from the Package version |
| **Defaults** | Safe default inputs used by products, offers, and direct installs |
| **Compatibility** | The install shape a workspace must satisfy before using the Package |
Packages do not own pricing, customer targeting, payment collection, or marketplace visibility. Those belong to Products and Offers.
## Package, Product, Offer
```text theme={null}
Package version
Input schema
Product
Marketplace listing or Offer
Order draft
Installation
Package Offer
Order draft
Installation
Direct install
Installation
```
Use this split when you design your catalog:
* Create or import a **Package** when you need a reusable install definition.
* Create a **Product** when that Package should become a sellable catalog item.
* Create an **Offer** when you want to send a customer a short URL with selected inputs, access rules, and commercial terms.
* Use a **Direct install** when the Package should run internally without Product or Offer wrapping.
## Input schemas
Akua exports each Package version's `Input` schema to drive generated forms. Docstrings become help text. `@ui(...)` annotations control grouping, ordering, widget hints, placeholders, and numeric bounds.
For authoring details, see [Package format](/akua/package-format). For the customer-facing generated form, see [Offers](/marketplace/offers).
## API workflows
Use the Packages API when your automation needs to create or maintain Package records outside the dashboard.
| Goal | Endpoint | Result |
| -------------------------------------------------------------------- | ------------------------------ | --------------------------------------------------- |
| Create a hosted Package from a supported source such as a Helm chart | `POST /packages` | Starts Package creation and returns an operation |
| Register an already-published OCI-backed Package | `POST /packages:import` | Creates the Package and its first immutable version |
| Add another version to an existing OCI-backed Package | `POST /packages/{id}/versions` | Creates a new immutable Package version |
`POST /packages:import` and `POST /packages/{id}/versions` are for Packages that have already been published to an OCI registry. Your workspace must have published Package import access to use either endpoint. The API still requires you to send the version, immutable content reference, and input schema. Akua inspects the published artifact and rejects the request if the artifact metadata doesn't match the values you send.
Public registries work without a saved credential. For private registries, add an active workspace registry credential that matches the registry or repository prefix before you import the Package.
### Import a published Package
To import a published Package, your workspace must have published Package import access. Use `Akua-Context` when your token can access more than one workspace, and send an `Idempotency-Key` so the request is safe to retry.
```bash theme={null}
curl https://api.akua.dev/v1/packages:import \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Akua-Context: ws_xxx" \
-H "Idempotency-Key: import-codezero-1-2-3" \
-H "Content-Type: application/json" \
-d '{
"name": "codezero",
"description": "Codezero Package",
"oci_ref": "oci://ghcr.io/example/packages/codezero",
"version": {
"semver": "1.2.3",
"ref": "sha256:abc123...",
"input_schema": {
"type": "object",
"properties": {
"license_key": { "type": "string" }
}
}
}
}'
```
The response is the created Package. Store its `id`; you need it to add future versions, create Products, create Offers, or install the Package directly.
If you retry with the same `Idempotency-Key` and the same body, Akua returns the same imported Package. If you reuse the key with different Package or version data, Akua returns a conflict so your automation doesn't accidentally point one retry key at two different artifacts.
### Add versions to an imported Package
After an OCI-backed Package exists, add later published versions with `POST /packages/{id}/versions`. This endpoint uses the same published Package import access as the initial import.
```bash theme={null}
curl https://api.akua.dev/v1/packages/pkg_xxx/versions \
-H "Authorization: Bearer $AKUA_API_TOKEN" \
-H "Akua-Context: ws_xxx" \
-H "Content-Type: application/json" \
-d '{
"semver": "1.2.4",
"ref": "sha256:def456...",
"input_schema": {
"type": "object",
"properties": {
"license_key": { "type": "string" }
}
}
}'
```
Direct version creation only applies to OCI-backed Packages. You still provide the immutable content reference and `input_schema` for each version, and Akua verifies both values against the published artifact before registering the version. Hosted Packages created through `POST /packages` publish versions through their Package creation flow.
## API
Manage Packages programmatically from the generated API reference. To run a Package without wrapping it in a Product, create a direct installation from the Installs API.
Create Packages, import published Packages, add versions, and fetch input schemas.
Register an OCI-backed Package and its first immutable version.
Add another immutable version to an existing OCI-backed Package.
Wrap a Package into a sellable product.
Create private or reusable sales paths for a Product or Package version.
Run a Package version as a direct installation.
## Related topics
Turn a Package into a sellable catalog item.
Author `package.k`, `Input`, and `@ui` annotations.
See how a Package version materializes for each install.
Send customers a short URL into the generated install wizard.
# Platform
Source: https://docs.akua.dev/platform
Manage workspaces, organizations, billing, security, notifications, quotas, and cloud ownership
Platform covers the shared controls around Akua: workspaces, organizations, billing, notifications, access, secrets, registry credentials, quotas, cloud ownership, and dashboard tooling.
Use this section when you are setting up a team, securing infrastructure, managing billing, or operating across multiple customer or environment workspaces.
Organize products, clusters, installations, members, and billing.
Manage team identity and customer workspace relationships.
Understand secrets, access decisions, and private registry controls.
Understand which infrastructure Akua manages and which parts stay in your cloud.
Understand workspace limits and allocation boundaries.
## Common paths
* Start with [Workspaces](/workspaces) to understand ownership and isolation.
* Use [Organizations](/platform/organizations) when your team or seller account manages multiple workspaces.
* Read [Security](/platform/security) before connecting credentials or private registries.
* Read [Bring your own cloud](/platform/byoc) to understand residency and feature boundaries.
* Check [Quotas and limits](/platform/quotas) when planning capacity.
# Bring your own cloud
Source: https://docs.akua.dev/platform/byoc
How Akua splits ownership between its managed control plane, your workers, and your cloud credentials
Akua's ownership model is split on purpose. Akua operates the control plane, and your workloads run on dedicated worker environments: Akua-managed machines, BYOM machines in your cloud account, manually attached workers, or imported clusters. That keeps the line clear between platform operations and your runtime environment.
## What Akua manages
Akua manages the platform control plane. It stores workspace settings, deployment configuration, policy state, and the references needed to operate your clusters and credentials.
Today, that managed control plane is the default model. A customer-hosted control plane is a future dedicated-mode option, not the standard deployment model.
## What you keep
Your worker environment keeps the parts that matter most to your business:
* **Worker machines and imported clusters**: manually attached workers, BYOM-provisioned machines, and clusters you import into Akua continue to run in your infrastructure.
* **Application runtime data**: databases, files, queues, user content, and other live application data stay where your workloads run.
* **Cloud accounts**: when you use BYOM, your cloud provider account pays for the compute and owns the underlying resources.
* **Secret plaintext**: Akua stores workspace-scoped secret references. Plaintext is only accessed through explicit secret access paths and is audited.
## BYOM cloud credentials
BYOM is Akua's bring-your-own-machine path. When you use it for managed provisioning, you connect a workspace-scoped cloud key so Akua can create and manage compute in your account. The credential is not a shared platform secret; it is tied to your workspace, and Akua uses it only for the operations you permit.
This model is useful when you want:
* Billing to stay in your own cloud account.
* Region or provider choice to stay under your control.
* A clear boundary between Akua's management layer and your infrastructure.
## What may pass through Akua
Some features need to process specific data outside your worker environment when you enable them. Those features are opt-in, and you can decide whether the tradeoff fits your compliance posture.
* **Log streaming**: container output passes through Akua so you can inspect and search logs.
* **Preview domains**: HTTP requests and responses pass through the edge delivery path that powers previews.
* **Dashboard access and API proxying**: cluster metadata, status, and command responses can pass through Akua to support remote inspection.
* **AI code execution**: code you submit and the output it produces are processed to provide the feature.
If you need a strict boundary, keep those features turned off and work directly against your own infrastructure.
## Related topics
See the residency caveats, secret handling, and access model in one place.
Connect your own servers to an Akua-managed cluster.
Compare Akua-managed compute with BYOM compute.
Keep image credentials scoped to your workspace.
# Notifications
Source: https://docs.akua.dev/platform/notifications
Stay informed about important events in your Akua account
Akua sends notifications for important events like machine expiry reminders, cluster status changes, and quota warnings. Notifications are delivered through two channels: email and the in-dashboard notification center.
## Notification center
The notification center is the bell icon in the top-right corner of your dashboard. It shows a count of unread notifications and opens a panel with your recent activity.
Each notification includes:
* A **severity indicator** (blue for info, amber for warnings, red for critical).
* A **title** and short description.
* A **timestamp** showing when the event occurred.
* A **link** to the relevant resource (click to navigate directly).
### Managing notifications
* **Mark as read**: click any notification to mark it as read and navigate to the resource.
* **Mark all as read**: use the button at the top of the panel to clear all unread indicators.
## Email notifications
Akua sends email notifications to the workspace owner's email address. Emails include a summary of the event and a link to the dashboard.
## Notification types
| Event | Severity | Description |
| ------------------------- | -------- | -------------------------------------------------------- |
| Machine expiry (5 days) | Warning | Akua-managed free tier machine will be deleted in 5 days |
| Machine expiry (2 days) | Warning | Machine will be deleted in 2 days |
| Machine expiry (24 hours) | Warning | Machine will be deleted in 24 hours |
| Cloud credential invalid | Warning | A BYOM cloud provider API token failed hourly validation |
## API
Manage notifications programmatically.
List, count, and mark notifications as read.
Mint API tokens for programmatic access.
## Related topics
Akua-managed compute machine lifecycle and expiry.
Understand resource limits and how to increase them.
Compare plans and understand free tier limits.
How Akua provisions and manages cloud servers.
# Organizations
Source: https://docs.akua.dev/platform/organizations
Give your company a shared identity, centralized member management, and the ability to manage customer workspaces on their behalf
An organization represents your company in Akua. It gives your team a shared identity, centralized member management, and the ability to manage customer workspaces on their behalf.
Every workspace belongs to an organization. During onboarding, Akua creates the first organization automatically so individual users and small teams can start in a workspace without thinking about company setup. As the team grows, the same organization becomes the place to manage members, customer workspace access, and shared identity.
## What organizations enable
### Sell and manage software for your customers
If you build software that your customers install through Akua, organizations let you manage those customer installations. Your team gets admin access to customer workspaces, so you can ship updates, monitor health, and troubleshoot issues, all while the customer retains ownership and billing control.
### Centralized team access
Add a team member to your organization once, and they automatically get access to every workspace your organization manages. When someone leaves, removing them from the organization revokes access everywhere. No need to update each workspace individually.
### Customer-first ownership model
Your customers always own their workspaces. They control billing, can add their own team members, and can revoke your access at any time. Your organization gets scoped admin access to their specific workspace, not their entire account.
## How it works
Set up an organization for your company with a name and optional slug.
Add team members with roles: owner, admin, or member. Everyone in the organization shares the same access to managed workspaces.
When a customer grants your organization access to their workspace (through an Offer or workspace settings), all your team members automatically get admin access.
## Managed workspaces
When a workspace is linked to your organization:
* All organization members get **admin** access to the workspace.
* The workspace owner retains full control, including billing and deletion.
* The workspace owner can revoke your access at any time.
Managed workspaces appear separately in the sidebar under "Shared With Me", keeping your own workspaces distinct from customer workspaces you manage.
## Organization roles
| Role | What they can do |
| ---------- | ----------------------------------------------------------------- |
| **Owner** | Full control — delete organization, manage roles, update settings |
| **Admin** | Manage members, update organization settings |
| **Member** | Access all managed customer workspaces with admin permissions |
## API
Manage organizations programmatically.
Endpoints, parameters, response shapes, try-it playground.
Mint API tokens for programmatic access.
## Related topics
Workspace roles and member management.
Set up API tokens for programmatic access.
Compare plans and understand workspace limits.
How Akua isolates workloads and protects data.
# Private container registries
Source: https://docs.akua.dev/platform/private-registries
Configure authentication for private container registries to install applications with private images
Clusters need credentials to pull private container images. Akua's registry proxy centralizes this: configure your registry credentials once, and all installs pull private images without storing credentials on clusters.
All image pulls through the proxy require authentication. You must configure credentials for any registry you want to proxy, including public registries like Docker Hub.
## Why use the registry proxy
* **Centralized credentials**: add your GitHub PAT or registry password once, use it across all clusters.
* **Credentials stay in Akua's secret store**: upstream registry passwords and tokens are stored as versioned workspace secrets and never sent to clusters directly.
* **Instant revocation**: disable access immediately without rotating credentials everywhere.
* **Audit trail**: see which installs pulled which images and when.
### For marketplace products
When selling products with private images, the proxy is especially valuable:
* Customers can pull your images without knowing your credentials.
* You can revoke a customer's access without affecting others.
* Your credentials give access to all your repos, but customers only get access to what they purchased.
## How it works
Akua runs a registry proxy at `oci.akua.dev`. When clusters pull images through this proxy, Akua validates the request using install-scoped credentials, looks up your workspace's upstream registry credentials, forwards the request to the upstream registry with your credentials, and streams the response back to the cluster.
Your upstream credentials (GitHub PAT, Docker Hub token, and so on) never leave Akua's infrastructure.
```mermaid theme={null}
flowchart TB
subgraph cluster["Your Cluster"]
pod["Pod pulls image\nwith install token"]
end
subgraph proxy["oci.akua.dev"]
p["Validates token\nAdds workspace creds"]
end
subgraph upstream["Upstream Registry"]
registry["ghcr.io / docker.io\nECR / etc."]
end
pod --> p --> registry
```
## Using the proxy in your images
To pull images through Akua's proxy, prefix your image references with `oci.akua.dev/`:
```yaml theme={null}
# Original image reference
image: ghcr.io/your-org/your-app:v1.0.0
# Through Akua proxy
image: oci.akua.dev/ghcr.io/your-org/your-app:v1.0.0
```
The format is: `oci.akua.dev/{upstream-registry}/{repository}:{tag}`
### Marketplace products
When building products for the marketplace, reference private images through the proxy in your Package resources or source inputs:
```yaml theme={null}
image:
repository: oci.akua.dev/ghcr.io/your-org/your-app
tag: v1.0.0
```
This ensures customers can deploy your product without needing access to your private registry.
### Generated package installs
When a Package references private images, Akua handles the proxy routing automatically. Configure workspace credentials in **Settings → Registries** with a PAT that has `read:packages` scope, and Akua detects image references in Package inputs, image sources, and chart-source values before routing pulls through the proxy at install time.
You can control this behavior per product with the **Registry Proxy Mode** setting:
* **Auto** (default): only proxy images from registries with configured credentials.
* **Always**: proxy all images from known registries (ghcr.io, docker.io, and so on).
* **Never**: do not rewrite any image URLs.
## Setting up registry credentials
Navigate to **Settings → Registries** in your workspace.
Click **Add Registry** and enter a friendly name, the registry hostname (for example, `docker.io` or `ghcr.io`), and the authentication type.
Standard authentication used by most registries. Enter your registry username and password or access token.
Used by: Docker Hub, Harbor, Nexus, JFrog Artifactory.
Token-based authentication for registries that use personal access tokens. Enter your PAT with read permissions.
Used by: GitHub Container Registry (ghcr.io), GitLab Container Registry.
OAuth2 client credentials for enterprise registries. Enter your client ID, client secret, and token URL.
Used by: some enterprise registry configurations.
Akua validates your credentials before saving. If validation fails, check that your credentials have pull access to the registry.
## Supported registries
| Registry | URL | Auth type | Notes |
| ----------------------------- | ------------------------------------------ | ----------------- | -------------------------------------------------------- |
| **Docker Hub** | `docker.io` | Username/password | Use access token instead of password for better security |
| **GitHub Container Registry** | `ghcr.io` | Token | Use a PAT with `read:packages` scope |
| **Amazon ECR** | `.dkr.ecr..amazonaws.com` | AWS credentials | Access Key ID, Secret Access Key, and region |
| **Google Container Registry** | `gcr.io` | Service account | Username `_json_key`, password is service account JSON |
| **Azure Container Registry** | `.azurecr.io` | Username/password | Use service principal or admin credentials |
| **GitLab Container Registry** | `registry.gitlab.com` | Token | Use a PAT or deploy token with `read_registry` scope |
| **Quay.io** | `quay.io` | Token | Use robot accounts for automation |
For other OCI-compliant registries (Harbor, JFrog Artifactory, Nexus, and so on), use the **Custom Registry** option with basic authentication.
For production use, create dedicated service accounts or robot accounts with read-only access rather than using personal credentials.
## Managing access
### Workspace-level credentials
Registry credentials are configured at the workspace level:
* All installs in the workspace can access images from configured registries.
* Different workspaces can have different registry configurations.
* Credential updates automatically apply to all installs in the workspace.
### Syncing credentials to existing installs
When you add or update registry credentials, existing installs need to be synced. In **Settings → Registries**, click **Sync All** to push credentials to all active installs, or on an install's detail page click **Re-sync Registry Access** to update a specific install. New installs receive registry access automatically during installation.
### Revoking access
To revoke access to private images:
1. **Disable a credential**: toggle the credential to disabled in **Settings → Registries**. This immediately invalidates all install tokens using that credential. Pods fail to pull images until the credential is re-enabled.
2. **Delete a credential**: permanently removes the credential. Existing install tokens become invalid immediately.
Disabling or deleting credentials takes effect immediately. Running pods are not affected, but any new pod starts or image pulls fail until valid credentials are configured.
### Per-install tokens
Each install receives a unique token for authenticating with the registry proxy. Revoking one install's access does not affect others, and deleting an install automatically revokes its registry token.
## Security
Your upstream registry credentials are stored as versioned workspace secrets and never sent to clusters directly. Clusters receive install-scoped tokens that only work with Akua's proxy and cannot be used directly against upstream registries.
Each install receives a unique token. If a cluster is compromised, you can revoke just that install's token without affecting others.
Disable a workspace credential to immediately block all image pulls. No need to rotate tokens across multiple clusters or wait for caches to expire.
Only workspace members can view or modify registry configurations. Credentials are never displayed after saving; only the registry name and URL are visible.
Akua logs all image pull operations, giving you visibility into which images are being accessed, by which install, and when.
## Troubleshooting
Common causes: credentials do not have pull access to the repository, the registry URL does not match the image reference, the token has expired, or the image URL is not using the proxy format (`oci.akua.dev/...`).
To resolve: verify your credentials work locally with `docker login`, check that image references use the proxy format, and update credentials in Akua if they have expired.
If newly added credentials are not working for existing installs, go to the install's detail page and click **Re-sync Registry Access**, or use **Sync All** in **Settings → Registries**.
Common causes: incorrect username format, token missing required scopes, or OAuth client misconfiguration. Check the registry's documentation for the correct authentication format and required permissions. For GitHub, ensure your PAT has `read:packages` scope.
If you hit registry rate limits, ensure your credentials have appropriate permissions. For Docker Hub, authenticated users have higher rate limits than anonymous access.
## API
Manage registry credentials programmatically.
List, create, and delete registry credentials.
Manage the underlying workspace secrets used by registry credentials.
## Related topics
Reference private images from Package resources.
How Akua stores and rotates credentials.
How applications are installed.
How workspaces organize your resources.
# Quotas and limits
Source: https://docs.akua.dev/platform/quotas
How Akua manages resource limits, provisioning speed, and API usage
Akua uses three types of limits to protect your account, keep costs predictable, and ensure fair access for all users. For a full comparison of what each plan includes, see [plans and pricing →](/pricing).
| Limit type | What it controls | Example |
| ---------------------- | ------------------------------------------ | ------------------------------------ |
| **Resource quotas** | How many resources you can own at once | Max 3 machines per workspace |
| **Concurrency limits** | How many operations can run simultaneously | Max 3 machines launching per cluster |
| **Rate limits** | How many API calls per time window | Cloud provider API calls per minute |
## Resource quotas
Resource quotas cap the total number of resources you can have at any time. When you reach the limit, new creation requests are rejected until you delete an existing resource or increase your limit.
Quotas are enforced **per user**, not per workspace. If you are a member of multiple workspaces, your usage across all of them counts toward a single limit. Creating a new workspace does not give you additional resources.
### Current limits
For the per-plan numbers (managed clusters, machines, CPU, memory, machine lifetime), see the canonical [plan comparison on the pricing page →](/pricing#plan-comparison). This page covers the quota model itself; pricing covers what each tier includes.
### Check your quotas
Use the API to see your current usage and limits.
List and inspect quota usage for your account.
Compare plans and understand resource limits per tier.
The response includes each metric's name, current usage, limit, and remaining capacity. Metric names contain a forward slash (for example, `compute/machines`). URL-encode the slash as `%2F` when using the single-metric endpoint. To include concurrency quotas (which are per-cluster), pass a `cluster_id` query parameter.
The `AKUA_API_TOKEN` environment variable holds your API token. This name is intentional: it is the canonical token variable for the Akua CLI and API.
## Concurrency limits
Concurrency limits cap how many operations of the same type can be in progress at the same time. Unlike resource quotas (which count what you *own*), concurrency limits count what is currently *launching*.
### Machine provisioning
Akua limits the number of machines that can provision simultaneously for a single cluster. If a cluster already has machines launching, additional requests are queued and retried automatically.
| Plan | Max concurrent provisions per cluster |
| ---- | ------------------------------------- |
| Free | 1 |
| Pro | 3 |
This prevents scenarios where repeated provisioning failures create a wave of requests that consume resources without producing healthy machines. Once a machine finishes launching and becomes ready, its slot opens up for the next machine in the queue.
Concurrency limits apply to both Akua-managed and BYOM machines. They protect your cluster infrastructure regardless of who pays for the compute.
### Failure backoff
If machine provisioning fails repeatedly for a cluster, Akua automatically backs off with increasing wait times between retries. This avoids overloading a provider that is already struggling and reduces unnecessary costs.
The backoff follows an exponential pattern: 30 seconds, then 1 minute, 2 minutes, up to a maximum of 5 minutes between retries. Backoff resets when provisioning succeeds or the instance type offering changes (for example, after a plan upgrade).
## Rate limits
Akua rate-limits cloud provider API calls to stay within provider quotas. This is handled transparently; you do not need to configure anything. If machines take slightly longer to provision during high demand, the rate limiter is spacing requests to avoid provider throttling.
## Bring your own cloud key (BYOM)
Machines provisioned with your own cloud provider API key ([BYOM](/compute/overview#bring-your-own-cloud-key)) are **not subject to resource quotas** (machine count, CPU, memory). You pay the provider directly, so Akua does not limit the total number of machines.
Concurrency limits and rate limits **still apply** to BYOM machines. These protect your cluster and cloud provider account from provisioning storms regardless of billing arrangement.
## Increasing your limits
There are three ways to increase your resource limits:
* **Upgrade to Pro**: higher limits for all metrics. See [plans and pricing →](/billing/tiers).
* **Bring your own key**: bypass resource quotas entirely by using your own cloud provider API key.
* **Enterprise overrides**: custom per-workspace or per-user limits set by the Akua team. Contact us if you need limits beyond what Pro offers.
Enterprise customers can request custom quota overrides that take precedence over plan defaults. Overrides can be scoped to a specific workspace or user. Reach out to your account team or email [support@akua.dev](mailto:support@akua.dev).
## Related topics
Compare plans and understand what each tier includes.
How Akua provisions machines and what the two provisioning modes are.
Understand cluster types and how quotas apply to them.
Inspect quota usage programmatically.
# Security
Source: https://docs.akua.dev/platform/security
How Akua isolates workloads, protects data, and keeps your infrastructure secure
Akua is built for deploying software into isolated customer environments: Akua-managed machines, BYOM machines in your cloud account, manually attached workers, and imported clusters. Security is foundational to the architecture, not an add-on, and the exact data path depends on the deployment mode and features you enable.
## Your data path depends on compute mode
Unlike platforms that run every workload on one shared application runtime, Akua separates the platform control plane from the worker environment where applications run.
```
Traditional PaaS: Your app → Shared provider runtime
Akua: Your app → Isolated worker environment
```
On Akua-managed machines, workloads run on dedicated machines Akua provisions in its managed provider account. With BYOM, manually attached workers, or imported clusters, workloads run in infrastructure you own or operate. In all modes, Akua's control plane stores configuration metadata such as deployment settings, chart values, and resource names so it can operate the platform.
## Isolation model
### Per-customer cluster isolation
Every managed cluster is a fully isolated virtual cluster with its own:
* Kubernetes API server
* Isolated state store (separate from other clusters)
* RBAC and service accounts
* Certificate authority
Cluster state is isolated: one customer's workloads cannot see, access, or interfere with another customer's workloads. Each virtual cluster has its own API server and data store, even though they share the underlying management infrastructure.
### Workspace isolation
Workspaces are the organizational boundary in Akua. Each workspace has:
* Separate Stripe billing (merchant account for marketplace sellers)
* Independent resource quotas
* Own cloud credentials (BYOM keys are workspace-scoped)
* Separate clusters, products, and installs
## Deployment modes
### Managed control plane
Today, Akua operates the control plane for the platform. That means Akua handles orchestration, policy, and workspace state. Runtime data stays in the worker environment for the selected compute mode unless you enable a feature that routes specific traffic or output through Akua.
### Customer workers and imported clusters
You can keep workloads on customer-owned workers, dedicated workers, or imported clusters. In those setups, the worker side of the deployment remains in your environment, and Akua only receives the platform data needed to manage it.
## Secrets and credentials
Akua uses a workspace-scoped secret store for runtime credentials. This applies to cloud provider API keys, container registry credentials, webhook signing secrets, and agent provider keys.
Key properties of the secret store:
* **Plaintext is never stored in configuration metadata.** Secret values are stored in an external secrets manager; Akua keeps only a reference.
* **Versioned rotation.** Secrets support append-only versioning: rotate by adding a new version and moving the `current` alias. Previous versions are accessible until explicitly disabled or destroyed.
* **Separate access scope.** Reading secret metadata (`secrets:read`) and reading plaintext (`secrets:access`) are separate scopes. Every plaintext access attempt is audited.
* **Soft delete with recovery.** Deleted secrets enter a 30-day recovery window before permanent removal.
See the [Secrets API →](/api-reference/secrets/list-secrets) for the full resource model.
## Data residency
BYOM is Akua's bring-your-own-machine path. For managed machine provisioning, you configure it with a cloud provider key so compute runs in your cloud account instead of Akua's provider account:
* **Choose from supported providers**: Akua-managed and BYOM machine provisioning use the providers available in your dashboard. Hetzner Cloud is available today.
* **Run your own workers where you need them**: manually attached workers and imported clusters can run in the regions and environments you operate.
* **Keep runtime data in the worker environment**: Akua's managed control plane sends orchestration commands, but it does not need direct access to your application data unless you enable a feature that explicitly processes it.
| Feature | What passes through Akua | Customer data visible? |
| --------------------------------- | ---------------------------------------- | ------------------------------------------------------------------ |
| **AI code execution** (Code Mode) | Your code snippets and execution results | Yes (code you write is processed) |
| **Custom dashboards** | Kubernetes API queries and responses | Only resource metadata (pod names, statuses), not application data |
| **Kubernetes API proxy** | `kubectl` commands and responses | Cluster metadata only (not application payloads or volumes) |
| **Log streaming** | Container stdout/stderr | Depends on what your app logs; avoid logging sensitive data |
| **Preview domains** | HTTP traffic (TLS terminated at edge) | Request/response passes through Cloudflare, not Akua servers |
These features are opt-in. If you want to minimize routed data, keep them off and access your cluster directly via its kubeconfig.
For the strictest requirements, customers can run workers on their own on-premise servers. Run the [bootstrap command →](/clusters/add-workers) and the server joins Akua's managed cluster. Keep optional features disabled if you need runtime data to remain inside your environment.
## Encryption
| Layer | Protection |
| --------------------------- | ----------------------------------------------------------------------------------------------------------- |
| **Control plane ↔ worker** | TLS with automatic certificate rotation |
| **API access** | HTTPS only, TLS 1.2+ |
| **Authentication** | OAuth2, session tokens, ServiceAccount JWTs |
| **Cloud credentials** | Stored as references to an external secrets manager (actual tokens are never in the configuration database) |
| **Worker bootstrap tokens** | Short-lived, configurable expiry |
## Authentication and access control
* **Dashboard**: OAuth2 via GitHub, Google, or email magic link.
* **API**: Workspace API tokens or OAuth2 Bearer (JWT) tokens.
* **Internal services**: Kubernetes ServiceAccount JWT with JWKS verification.
* **Workspace membership**: Role-based (owner), scoped to workspace resources.
## What Akua stores versus what stays on your infrastructure
**Stored by Akua** (configuration metadata):
* Workspace settings, user accounts, billing state.
* Product definitions, Helm chart references, installation configurations.
* Helm value overrides you configure in the dashboard.
* Machine records, cluster metadata, quota usage counters.
**Stays on your infrastructure** (runtime data):
* Your application runtime data (databases, files, user-generated content) in the selected worker environment.
* Your container images (stored in your registry; Akua only stores the image reference).
* Your Kubernetes secrets (stored in your cluster's isolated data store).
* Your cloud provider API tokens (stored as references to an external secrets manager, not in Akua's configuration database).
## On-premise and air-gapped environments
Akua supports deploying to servers behind firewalls and in restricted networks:
1. The customer's server initiates an **outbound-only** connection to the Akua control plane.
2. No inbound ports need to be opened.
3. The bootstrap command handles all setup (Kubernetes install, cluster join, certificate exchange).
4. Once connected, the worker communicates through a secure tunnel back to the control plane.
This means hospitals, banks, and government agencies can use Akua without exposing their infrastructure to the internet.
## Compliance roadmap
Akua does not yet hold SOC 2, ISO 27001, or other formal certifications. These are planned and in progress. We are transparent about our current state.
| Certification | Status | Timeline |
| --------------------------------------------- | ---------------------------------------------------------------------- | --------- |
| **GDPR** | Architecture supports EU data residency; formal assessment in progress | Current |
| **SOC 2 Type II** | Planned | 2026–2027 |
| **ISO 27001** | Planned | 2026–2027 |
| **DORA** (Digital Operational Resilience Act) | Under evaluation | TBD |
For enterprise customers requiring compliance documentation before formal certification, Akua provides:
* Architecture security review documentation.
* Data flow diagrams showing isolation boundaries.
* Infrastructure audit support (we participate in your vendor assessment).
* Custom DPAs (Data Processing Agreements).
## Reporting vulnerabilities
If you discover a security vulnerability, report it to **[security@akua.dev](mailto:security@akua.dev)**. We take all reports seriously and will respond within 48 hours.
## Related topics
Bootstrap command for connecting your own servers.
Ownership model for managed control planes, customer workers, and BYOM credentials.
Manage workspace secrets and credential rotation.
Keep image credentials scoped to your workspace.
# Pricing
Source: https://docs.akua.dev/pricing
Compare Akua plans, understand usage-based billing, and find the right tier for your workloads
Akua offers a generous free tier and a Pro tier for larger workloads. Both tiers include the full platform with no feature gates. The difference is resource limits and machine lifetime.
All plans include the full Akua platform: marketplace, products, private registries, custom dashboards, CLI, and API access. There are no feature gates; only resource limits differ.
## Plan comparison
| | Free | Pro |
| ---------------------------- | ------------ | ------------------ |
| **Managed clusters** | 1 | 3 |
| **Akua-managed machines** | 1 | 3 (included) |
| **CPU cores** | 2 vCPUs | 8 vCPUs (included) |
| **Memory** | 4 GiB | 16 GiB (included) |
| **Code executions** | 10,000 / day | 50,000 / day |
| **Machine lifetime** | 7 days | Unlimited |
| **Products and marketplace** | Unlimited | Unlimited |
| **Workspaces** | Unlimited | Unlimited |
| **Private registries** | Included | Included |
| **Custom dashboards** | Included | Included |
Pro tier limits represent what's **included in your subscription**. Usage beyond the included amount is billed per resource.
## Free tier
The free tier includes a managed cluster, a machine, and the full platform. That's enough to run a small production app, sell through the marketplace, and serve real customers. No credit card required.
**Machine lifetime:** Akua-managed machines on the free tier are automatically deleted after 7 days. You'll receive [notifications](/platform/notifications) at 5 days, 2 days, and 24 hours before deletion. To remove the time limit, bring your own cloud key or upgrade to Pro.
## Pro tier
Pro includes more machines and higher resource limits, with no machine lifetime restriction. Usage beyond the included limits is billed per resource.
## Bring your own cloud key
Connect your own cloud provider API key (for example, a Hetzner Cloud token) and **compute quotas don't apply**. You pay the provider directly at their published rates; Akua manages the Kubernetes lifecycle with no markup on infrastructure costs. This works on every plan, including Free.
Cluster quotas still apply since Akua manages the control plane regardless of where your workers run.
[Learn about adding workers →](/clusters/add-workers)
## Workspace access states
Every workspace has an access state that reflects its subscription status: `active`, `payment_grace`, `restricted`, and so on. See [workspace access states](/billing/overview#workspace-access-state) for the full table and what each state allows. Read the current state from the [API](/api-reference/workspaces/get-workspace-access-state) at any time.
## Increasing your limits
Compare plans and upgrade.
Request enterprise limits.
## API
Manage subscriptions and check access state programmatically.
Subscription, access state, billing portal, and tier-change endpoints.
Query active feature entitlements for a workspace.
## Related topics
Upgrade, cancel, and manage your subscription.
Understand resource limits and check usage.
Prepare commercial product distribution with private offer links.
Bypass compute quotas with your own cloud key.
# Sellable products
Source: https://docs.akua.dev/products
Wrap a Package into a sellable product for the marketplace or private offers
Products are sellable wrappers around [Packages](/packages). A Product gives a Package catalog metadata, marketplace visibility, and sale paths so customers can purchase and install your software through the marketplace or a private [Offer](/marketplace/offers).
A Product points at a Package version and controls how that Package is presented for sale. When a customer purchases, Akua creates an [order draft](/marketplace/order-drafts), provisions a [private installation repository](/installs/repositories) for that customer, and installs the selected Package version with the customer's inputs.
This page is about the Products you create and sell. For Akua's own platform capability catalog, see [Platform capabilities](/capabilities).
## How sellable products work
Products package your software for sale. Each Product includes:
* **Package binding**: the Package and version customers install
* **Display settings**: name, description, images, and visibility options
* **Sale paths**: public marketplace listing, reusable Offer, or private customer Offer
* **Commercial setup**: optional payment configuration for customer billing
When customers purchase your product, Akua automatically provisions a per-customer installation repository and applies the rendered manifests to the selected cluster. Each customer gets their own isolated installation with dedicated resources.
## How a product becomes an installation
```
Package version + product metadata
│
▼ customer purchases via offer or marketplace
Per-install repository (akua.toml + package.k + inputs.yaml + upstream/ + manifests/)
│
▼ cluster syncs
Running installation
```
Every installation gets its own repository with vendored sources, the customer's inputs, and the rendered Kubernetes manifests. The repository is the install target: your cluster reads from it, your team can edit it, and every change ships with a commit history. See [Concepts](/concepts) for the full picture.
## Products and offers
Products can appear in the marketplace or stay private behind [Offers](/marketplace/offers): shareable short URLs (`akua.dev/i/`) that take customers directly into the install wizard.
An Offer can pre-fill and optionally lock specific input fields. The wizard form is generated from the selected Package version's input schema, so customers configure their install without any hand-coded form on your part. Input schema quality (docstrings, grouping, ordering, widget hints) is the main lever for a great customer experience.
## When to use products
Use sellable products when you want to sell software to customers:
* **Open source monetization**: offer managed, dedicated installations of your OSS project (databases, dev tools, analytics, CMS) as a cloud service without building multi-tenant infrastructure
* **SaaS with dedicated instances**: enterprise customers who need isolation get their own installation (healthcare, finance, collaboration tools)
* **Managed database services**: offer dedicated database clusters (PostgreSQL, Redis, ClickHouse) per customer
* **Custom applications**: B2B SaaS, industry-specific software, white-label solutions, or internal tools turned into products
## Sellable products vs direct installs
| | Sellable products | Direct installs |
| -------------------------- | ----------------------------------------- | -------------------------------------------- |
| **Purpose** | Sell software to customers | Internal tools, shared databases, monitoring |
| **Pricing** | Optional Stripe integration | No pricing |
| **Marketplace** | Listed when catalog visibility is enabled | Not listed |
| **Offers** | Yes (shareable install wizard links) | No |
| **Per-install repository** | Yes, one per customer | Yes, one per install |
Both flavors generate per-installation repositories from Package versions and inputs. Learn more about [installations →](/installs).
## Creating a product
Create a product from the [Products dashboard](https://akua.dev/products?create=product). You will:
1. Select an existing Package or create one from an authored `package.k` and supported package dependencies.
2. Choose the Package version that the Product should sell.
3. Add product metadata and decide whether the Product is public in the marketplace or only sold through private Offers.
4. Configure payment when the Product should collect money during checkout.
To collect payment, enable the workspace's commerce payment path, then configure the commercial terms used by the listing or Offer.
## API
Create, update, archive, and list products.
Create and manage offers for your products.
Create Packages, inspect versions, and fetch input schemas.
## Related topics
Manage versioned install definitions and input schemas.
Map Akua's platform catalog categories to docs areas.
Share short URLs that drive the generated install wizard.
How customer purchase journeys are tracked.
How products create customer installations.
Plans, quotas, and platform billing.
# Quickstart
Source: https://docs.akua.dev/quickstart
Create an Akua account, connect an agent, and let it start working from your workspace context
This quickstart gets Akua into the hands of an agent. You will create an account, open the dashboard, choose a workspace, connect an AI assistant, and ask it to use Akua on your behalf.
Use this path first if you are new to Akua. Product setup, clusters, installs, and commerce all come later; the first useful outcome is an agent that can see your workspace and guide the next action.
## Prerequisites
* An Akua account, created with email or social sign-in.
* Access to the Akua dashboard at [akua.dev](https://akua.dev).
* An MCP-compatible AI tool if you want to connect your own assistant.
* Hosted agent access in the dashboard if your workspace has dashboard agents enabled.
Create your account, sign in, and continue in the dashboard.
## What you'll do
Sign up or sign in at [akua.dev](https://akua.dev). Akua creates your user profile and takes you to the dashboard.
Choose or create the workspace the agent should help with. A workspace is the isolation and billing boundary for Products, clusters, installations, and agent access.
Use the hosted dashboard agent if it is available in your workspace, or connect your own MCP-compatible AI tool to the Akua Platform MCP server at `https://mcp.akua.dev`. The Platform MCP server opens an OAuth flow in your browser so the agent can act with your Akua account.
Add the Akua documentation MCP server at `https://docs.akua.dev/mcp` if your AI tool supports multiple MCP servers. This gives the agent current product docs alongside your workspace context.
Start with a general prompt so the agent can inspect what exists before it changes anything.
```text theme={null}
Summarize my Akua workspace and tell me the next three setup steps.
```
Use the agent's summary to choose the right follow-up: prepare compute, package software, create a Product, configure an Offer, or review capabilities.
## Connect your own AI tool
Configure these MCP servers in your AI tool when you want the assistant to work outside the Akua dashboard.
| Server | URL | Auth | Use it for |
| ----------- | --------------------------- | --------- | -------------------------------------------------------- |
| `akua` | `https://mcp.akua.dev` | OAuth 2.1 | Manage workspaces, clusters, Products, and installations |
| `akua-docs` | `https://docs.akua.dev/mcp` | None | Search current Akua documentation |
See [AI & Agents quick setup](/ai#quick-setup) for client-specific setup notes.
The Platform MCP server manages resources through the same API surface as the dashboard. Keep the OAuth grant scoped to the account and workspace you want the agent to use.
## Use the dashboard agent
If hosted agents are enabled for your workspace, the dashboard can run an agent for you. This is the shortest path when you do not want to configure a separate AI tool.
Open the dashboard, select your workspace, and open the agent surface. Start with the workspace briefing prompt above, then ask the agent to continue with a specific task.
Learn what dashboard agents can do and how their sessions work.
Use the dashboard to supervise agent sessions, tasks, and follow-up work.
## Next paths
After an agent can see your workspace, choose the path that matches the work you want it to help with.
Create managed Kubernetes infrastructure or connect a cluster you already operate.
Turn software source into a reusable Package version.
Wrap a Package version as customer-facing software.
Configure private Offer links and customer install paths.
Use hosted agents for dashboard work, runbooks, and ongoing operations.
Map Compute, Packaging, Delivery, Networking, Commerce, Agents, and Platform to the right docs area.
## Troubleshooting
Confirm your AI tool supports remote MCP servers and browser-based OAuth. Then reconnect `https://mcp.akua.dev` and allow the browser sign-in window to finish before returning to the tool.
Check that the tool is connected to both MCP servers. `https://docs.akua.dev/mcp` only searches documentation. Resource actions require the Platform MCP server at `https://mcp.akua.dev`.
Switch to the intended workspace in the dashboard, then reconnect or refresh the Platform MCP authorization in your AI tool. The grant should match the account and workspace you want the agent to use.
Hosted agents are enabled per workspace. Use your own MCP-compatible AI tool with the Platform MCP server, or ask a workspace administrator to confirm agent access.
## Related topics
Connect AI tools through MCP or use hosted agents in the dashboard.
Let an AI tool work with Akua resources through the platform server.
Understand the workspace boundary for users, resources, and billing.
See how Akua capabilities fit together across infrastructure, software delivery, commerce, and agents.
# Storage
Source: https://docs.akua.dev/storage
Choose persistent storage for the applications running in your clusters
Storage controls where stateful applications keep their data. Akua supports local-path storage for simple clusters and distributed storage options for more durable workloads.
Use this section when an application needs persistent volumes, databases, uploads, queues, or any workload that must keep data after a pod restarts.
Learn how storage classes and persistent volumes fit into clusters.
Use node-local storage for simple and low-cost installs.
Use replicated storage for workloads that need stronger durability.
Review storage-related resource boundaries.
# Docker Compose to Kubernetes converter
Source: https://docs.akua.dev/tools/compose-converter
Convert Docker Compose files to Kubernetes manifests and Helm charts
Access the Docker Compose to Kubernetes converter tool.
The Docker Compose to Kubernetes converter helps you migrate Docker Compose applications to Kubernetes by automatically generating Kubernetes manifests and Helm charts from your `docker-compose.yaml` files.
## What it does
The converter transforms Docker Compose services into Kubernetes resources:
* **Services** → Kubernetes Deployments and Services
* **Volumes** → PersistentVolumeClaims or other volume types
* **Networks** → Kubernetes Services with ClusterIP
* **Ports** → Service ports and optional Ingress resources
* **Environment variables** → ConfigMaps and Secrets
* **Health checks** → Liveness and readiness probes
The converter also generates a complete Helm chart with all resources bundled together, ready to deploy your converted application.
## When to use
Use the converter when:
* **Migrating from Docker Compose:** You have a working Docker Compose setup and want to deploy to Kubernetes.
* **Quick prototyping:** You want to quickly test a Docker Compose app on Kubernetes.
* **Learning Kubernetes:** You want to see how Docker Compose concepts map to Kubernetes resources.
* **CI/CD integration:** You need to convert Compose files as part of an automated pipeline.
The converter provides a good starting point, but you may need to adjust the generated manifests for production use. Review the generated resources and customize them based on your specific requirements.
## How to use
### Access the converter
The converter is available at [https://akua.dev/kompose](https://akua.dev/kompose). You can paste your Docker Compose YAML directly into the interface.
### Conversion options
The converter supports several options to customize the output:
* **Provider:** Choose Kubernetes or OpenShift.
* **Controller type:** Deployment, DaemonSet, or ReplicationController.
* **Replicas:** Number of pod replicas to create.
* **Volume type:** PersistentVolumeClaim, emptyDir, hostPath, or ConfigMap.
* **Namespace:** Target Kubernetes namespace.
* **Network policies:** Generate NetworkPolicy resources for service isolation.
* **Helm chart:** Generate a complete Helm chart (enabled by default).
### Output formats
The converter generates:
1. **Kubernetes manifests:** Individual YAML files for each resource (Deployments, Services, ConfigMaps, and others).
2. **Helm chart:** A complete Helm chart with:
* `Chart.yaml`: Chart metadata
* `values.yaml`: Configurable values
* `templates/`: All Kubernetes manifests as Helm templates
You can download the output as a ZIP file containing all generated files, or copy individual files from the interface.
## Example
Convert a simple web application with Redis:
**Input (docker-compose.yaml):**
```yaml docker-compose.yaml expandable highlight={2-8,10-13} theme={null}
services:
web:
image: nginx:latest
ports:
- "80:80"
environment:
- NODE_ENV=production
depends_on:
- redis
redis:
image: redis:alpine
ports:
- "6379:6379"
```
**Output (Kubernetes manifests):**
```yaml web-deployment.yaml expandable highlight={1-2,6-7,15-20} theme={null}
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
io.kompose.service: web
name: web
namespace: default
spec:
replicas: 1
selector:
matchLabels:
io.kompose.service: web
template:
metadata:
labels:
io.kompose.service: web
spec:
containers:
- env:
- name: NODE_ENV
value: production
image: nginx:latest
name: web
ports:
- containerPort: 80
protocol: TCP
restartPolicy: Always
```
```yaml web-service.yaml expandable theme={null}
apiVersion: v1
kind: Service
metadata:
labels:
io.kompose.service: web
name: web
namespace: default
spec:
ports:
- name: "80"
port: 80
targetPort: 80
selector:
io.kompose.service: web
```
```yaml redis-deployment.yaml expandable theme={null}
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
io.kompose.service: redis
name: redis
namespace: default
spec:
replicas: 1
selector:
matchLabels:
io.kompose.service: redis
template:
metadata:
labels:
io.kompose.service: redis
spec:
containers:
- image: redis:alpine
name: redis
ports:
- containerPort: 6379
protocol: TCP
restartPolicy: Always
```
```yaml redis-service.yaml expandable theme={null}
apiVersion: v1
kind: Service
metadata:
labels:
io.kompose.service: redis
name: redis
namespace: default
spec:
ports:
- name: "6379"
port: 6379
targetPort: 6379
selector:
io.kompose.service: redis
```
The converter generates Kubernetes manifests for each service, including Deployments and Services. When you enable Helm chart generation, it also creates a complete Helm chart with all resources bundled together.
## Limitations
The converter handles most common Docker Compose features, but some features are not supported or require manual adjustment:
| Feature | Status | Notes |
| ---------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **Build contexts** | Not supported | Docker Compose `build:` directives are not converted. Use pre-built container images instead. |
| **Docker Compose versions** | Limited support | Versions 2.1 and 3.2 have limited support due to their experimental nature. Use stable versions (1, 2, or 3) for best results. |
| **Docker-specific features** | Not supported | Some Docker-only features don't have direct Kubernetes equivalents and may be skipped or require manual configuration. |
| **Networking** | Converted with limitations | Docker Compose networks are simplified to Kubernetes Services. Complex network configurations may need manual adjustment. |
| **depends\_on** | Converted with limitations | Service dependencies are converted to init containers or startup order hints where possible, but exact startup ordering isn't guaranteed. |
| **Volumes** | Converted with limitations | Volume configurations are converted, but you may need to adjust volume types based on your requirements. |
| **Resource limits** | Converted with limitations | Basic resource constraints are converted, but you may want to add more detailed resource requests and limits for production use. |
## Related topics
Turn generated manifests into a reusable Package.
Deploy your converted application as a product.
How Packages materialize on clusters.
How Packages, products, and installations fit together.
# Workspaces
Source: https://docs.akua.dev/workspaces
How organizations contain workspaces, and how workspaces isolate clusters, products, billing, and installations
A workspace is the unit of resource ownership in Akua. Clusters, products, installations, billing, and Stripe payments all belong to a workspace. Switch between workspaces in the sidebar to navigate between sets of resources.
Workspaces are scoped to their members. Only people invited to a workspace, or members of an [organization](/platform/organizations) that manages it, can see it.
Every workspace sits inside an organization. Akua creates the first organization automatically during onboarding, so solo users can start from a workspace-first experience while still having a durable organization to grow into later.
## What a workspace contains
* **Clusters**: Kubernetes infrastructure for deploying applications.
* **Regions**: organizational labels for grouping clusters.
* **Products**: sellable software packages you create.
* **Installations**: running instances of your products and direct installs, each with its own [package repository](/installs/repositories).
* **GitHub App installations**: connected for automated installs.
* **Workspace members**: users with direct access.
* **Organization**: parent [organization](/platform/organizations) for team identity, member management, and managed customer workspace access.
* **Stripe account**: one billing account per workspace for marketplace payments.
## Workspaces vs organizations
These solve different problems. Use them together:
| | Workspace | [Organization](/platform/organizations) |
| ------------------ | ----------------------------------------------------------- | -------------------------------------------------- |
| **What it is** | Container for resources (clusters, products, installations) | Identity for your team, company, or seller account |
| **Who sees it** | Direct members and the managing organization's members | Members of the organization |
| **Owns billing** | Yes (Stripe Connect, Akua subscription) | No |
| **Owns resources** | Yes | Contains the workspaces that own resources |
| **Typical count** | One per environment, customer, or business unit | One per company |
If you're a single user shipping a product, onboarding creates the organization for you and keeps the experience focused on your first workspace. When you add teammates, customers, or more environments, that organization becomes the shared identity that ties those workspaces together. If you sell software that your customers install on Akua, your organization gets admin access to each customer's workspace through the [managed-by](/platform/organizations#managed-workspaces) relationship; your customers retain full ownership and billing control.
## When to use separate workspaces
Even with an organization, you'll often want multiple workspaces:
* **Environment separation**: production, staging, and development as separate workspaces prevent accidental changes and keep clusters isolated.
* **Per-customer ownership**: when you sell software, each customer gets their own workspace. They own it; your organization manages it. This keeps billing, data, and resources isolated per customer.
* **Independent business units**: different legal entities, different Stripe accounts, or different teams that should never share resources.
* **Test isolation**: short-lived workspaces for one-off projects, demos, or partner experiments.
Don't reach for a new workspace just to organize resources within the same business and same team. Clusters, products, and installations can coexist in one workspace.
## Workspace roles
Each member has a role that controls their permissions:
| Role | Permissions |
| ---------- | --------------------------------------------------------------------------------------- |
| **Owner** | Full control: delete workspace, manage billing, transfer ownership, and invite members. |
| **Admin** | Manage products, installations, clusters, secrets, and members. |
| **Member** | Deploy products and view resources and logs. |
The workspace creator is automatically assigned the **owner** role. Members of a managing organization get **admin** access automatically. See [Organizations → Managed workspaces](/platform/organizations#managed-workspaces).
## Managing the workspace
* Switch workspaces from the sidebar switcher.
* Selecting **All Workspaces** shows resources from every workspace you have access to.
* Create, edit, invite members, or transfer ownership from **Settings** in the dashboard.
## API
Manage workspaces, members, subscriptions, and access state programmatically.
CRUD, member management, subscription, access state, and billing portal endpoints.
Mint API tokens for programmatic access.
## Related topics
Team and customer-management identity.
Manage your workspace subscription.
Set up infrastructure in your workspace.
Resource quotas and plan limits per workspace.