Kvindo™ Cloud Docs
A few ideas explain how everything in Kvindo Cloud fits together. They apply whether you use the console, the CLI, Terraform, or the raw API.
A product is a family of functionality (Compute, Networking, S3, Kubernetes, …). A resource is a single thing you create inside a product — a VM, a VPC, a bucket. Every resource has the same envelope shape: apiVersion, kind, metadata (id, name, description, folder, labels), and spec (its desired configuration). Read-only state lives under status. Resource names are not required to be unique — even within a single folder two resources of the same type may share a name; the id (a ULID) is the true identifier.
Every resource lives in a folder — the platform's unit of grouping (much like a Kubernetes namespace), a purely conceptual way to organize resources by team, project, or environment. Folders do not by themselves grant or restrict access; access is controlled by IAM Access Policies, which can reference a resource's folder in a when expression when you want folder-scoped rules.
A Transaction creates a whole set of resources atomically — either the entire bundle is accepted or none of it is. It carries one array per resource kind, so an entire environment (folder + VPC + subnet + VMs …) can be described and submitted as a single declarative document. Applying a multi-document manifest with the CLI builds on the same idea.
Creating or changing a resource is asynchronous. When you submit a desired spec, the API records it and returns immediately; the resource starts in a pending state. A background reconciler for that resource type then runs in a continuous loop, comparing the desired state in the database with the actual state on the underlying hosting provider and taking whatever steps move the real resource toward what you asked for.
A resource therefore moves through states like Scheduled → Reconciling → Reconciled (or UnableToReconcile on error). This is why tools offer a wait option (e.g. kc apply --wait): it blocks until the reconciler reports the resource has reached its desired state. The same loop keeps resources converged over time, not just at creation.
Two fields track progress. status.state is the overall state of the resource:
| status.state | Meaning |
|---|---|
scheduling | Being created for the first time — the reconciler is provisioning it on the hosting provider. |
reconciling | An existing resource is being changed; the reconciler is applying the new desired spec. |
stable | Created and matching its desired state — ready to use. This is the normal resting state. |
schedulingfailed | Creation failed (e.g. invalid configuration or a provider error). Edit and retry, or delete the resource. |
rescheduling | A failed creation is being retried after the partial resources are cleaned up (used by some products, e.g. Kubernetes). |
queuedforreconciling | A change to an existing resource has been accepted and is waiting for the reconciler to pick it up. |
queuedfordeletion | A delete has been accepted and is waiting for the reconciler to pick it up. |
deleting | The reconciler is removing the resource from the hosting provider. |
deleted | The resource has been removed. |
Each change you submit also has its own progress, reported on status.lastChangeRequest.state — useful for watching a single create/update/delete:
| status.lastChangeRequest.state | Meaning |
|---|---|
queued | Accepted but not started yet — waiting for the reconciler to pick it up. |
reconciling | The change is being applied on the hosting provider. |
waitingfordeleteprecondition | A delete is on hold until a precondition is met (e.g. dependent resources still exist); status.lastChangeRequest.errorMessage says what is blocking it. |
reconciled | The change completed successfully. |
unabletoreconcile | The change failed — e.g. invalid configuration or a provider error. status.lastChangeRequest.errorMessage explains why. |
Beyond each resource's own spec, every resource shares the same metadata and status fields. (On a specific resource page, switch the dropdown to All fields to see these alongside that resource's spec.)
| UI Name | API / kc name | Terraform name | Optional | Format | Default | Is read only | Description |
|---|---|---|---|---|---|---|---|
| Id | metadata.id |
metadata.id |
Yes | ULID | — | After creation | Unique identifier; may be set on creation, immutable afterwards (server-generated if omitted) |
| Name | metadata.name |
metadata.name |
No | string, 3–32 chars, lowercase DNS label (^[a-z-][a-z0-9-]{2,31}$) |
— | No | The resource's name (not required to be unique — the id is the true identifier) |
| Description | metadata.description |
metadata.description |
Yes | string (nullable, up to 200 characters) | — | No | Free-form description |
| Folder | metadata.folderId |
metadata.folder_id |
Yes | ULID (nullable) | — | No | Folder this resource belongs to |
| Labels | metadata.labels |
metadata.labels |
Yes | map: keys 3–64 chars, lowercase, [a-z0-9-/.], not starting with a digit; values: string up to 2048 chars |
— | No | Key/value labels |
| Delete protection | metadata.deleteProtection |
metadata.delete_protection |
Yes | boolean (nullable) | — | No | Blocks deletion while enabled |
| State | status.state |
status.state |
— | string | — | Yes | Reconcile state |
| Create time | status.createTime |
status.create_time |
— | timestamp (RFC 3339) | — | Yes | When the resource was created |
| Created by user | status.createdByUser |
status.created_by_user |
— | object (nullable) | — | Yes | User who created the resource |
| Id | status.createdByUser.id |
status.created_by_user.id |
— | ULID (nullable) | — | Yes | User ULID |
| Name | status.createdByUser.name |
status.created_by_user.name |
— | string (nullable) | — | Yes | User name |
| Last change request | status.lastChangeRequest |
status.last_change_request |
— | object (nullable) | — | Yes | Most recent change request status |
| State | status.lastChangeRequest.state |
status.last_change_request.state |
— | string | — | Yes | Change request state |
| Create time | status.lastChangeRequest.createTime |
status.last_change_request.create_time |
— | timestamp (RFC 3339) | — | Yes | When the request was created |
| Error message | status.lastChangeRequest.errorMessage |
status.last_change_request.error_message |
— | string (nullable) | — | Yes | Error if the request failed |
| Created by user | status.lastChangeRequest.createdByUser |
status.last_change_request.created_by_user |
— | object (nullable) | — | Yes | User who made the request |
| Id | status.lastChangeRequest.createdByUser.id |
status.last_change_request.created_by_user.id |
— | ULID (nullable) | — | Yes | User ULID |
| Name | status.lastChangeRequest.createdByUser.name |
status.last_change_request.created_by_user.name |
— | string (nullable) | — | Yes | User name |
| Pricing | status.pricing |
status.pricing |
— | object | — | Yes | Pricing breakdown |
| Month | status.pricing.month |
status.pricing.month |
— | decimal | — | Yes | Price per 30-day month |
| Day | status.pricing.day |
status.pricing.day |
— | decimal | — | Yes | Price per day |
| Hour | status.pricing.hour |
status.pricing.hour |
— | decimal | — | Yes | Price per hour |
Resource docs
Guides
More in this section