CRD reference
Infrared keeps everything it knows in its own custom resources, so kubectl get shows you the same state the UI does. This page lists every kind, what it is for, and the fields worth knowing. Most of the time you change these through the UI, ir or the API, which check what you ask for before they write it. Read them here when you script against the cluster, debug a stuck object, or want to know exactly what a setting does.
All kinds are in the API group infrared.darkshift.io, version v1alpha1. Cluster-scoped kinds describe the control plane. Namespaced kinds belong to one org and live in its namespace, ir-org-<org>.
Most kinds also have status.observedGeneration and status.conditions (Ready, Progressing, Degraded). BreakGlass, User, GitConnector, Domain and Incident don't. The tables below leave these common fields out and list only the extra conditions a kind adds.
Resources Infrared creates carry the label app.kubernetes.io/managed-by: infrared. Org resources carry infrared.darkshift.io/org, and resources seeded from the catalog carry infrared.darkshift.io/catalog.
| Kind | Short name | Scope |
|---|---|---|
| Installation | irinst | Cluster |
| Organization | irorg | Cluster |
| Cluster | ircluster | Cluster |
| BreakGlass | none | Cluster |
| User | none | Cluster |
| GitConnector | none | Cluster |
| GitProvider | irgit | ir-org-<org> |
| GitopsRepo | irgitops | ir-org-<org> |
| Product | irproduct | ir-org-<org> |
| AgentRole | ar | ir-org-<org> |
| AgentWorkflow | aw | ir-org-<org> |
| AgentWorkflowRun | awr | ir-org-<org> |
| Release | irrel | ir-org-<org> |
| ReleaseCut | ircut | ir-org-<org> |
| Team | irteam | ir-org-<org> |
| Human | irhuman | ir-org-<org> |
| Domain | none | ir-org-<org> |
| Incident | irinc | ir-org-<org> |
| CloudAccount | cloudacct | ir-org-<org> |
| Registry | reg | ir-org-<org> |
Installation
The singleton that tracks the setup wizard and holds the install's own settings. It must be named infrared. The API fills in the spec as the wizard advances, and the operator works out the phase from it.
| Field | Meaning |
|---|---|
spec.tokenVerified | Set once someone has presented the one-time setup token. |
spec.admin.email | The root user's address. The root user is the first platform admin, made by the setup wizard, and its password's hash is in the BreakGlass named root. |
spec.admin.passwordSecretRef | Deprecated, and only on installs set up before BreakGlass existed. The API copies the hash from this Secret once, then clears the reference after you delete the Secret. |
spec.platformOrg | The Organization that administers the control plane. |
spec.managementCluster | The Cluster Infrared runs on. |
spec.gitProviderRef, spec.gitopsRepoRef | The platform org's GitProvider and GitopsRepo. |
spec.previews | How zones get their addresses. domain is the platform domain: a zone answers at https://<zone>.<domain>, except a Production zone named <product>-production or <product>-prod, which answers at https://<product>.<domain>. A wildcard DNS record for the domain must point at the management cluster's ingress. signInURL is Infrared's public https:// address, where visitors sign in. ingressHost and ingressIP are what an org's own domains point at, with a CNAME or an A record. See the rows below for the rest. |
spec.previews.managedRoots[], cloudflareTokenSecret, cloudflareTokenKey | Domains Infrared manages in Cloudflare, under which any org can claim a subdomain, and the Secret in Infrared's namespace (and its key, api-token by default) that holds a token allowed to edit their DNS. See Domains and addresses. |
spec.previews.customHostnames, acmeEmail, domainTokenKey | On the gateway edge behind Cloudflare: serve addresses under an org's own domains as Cloudflare for SaaS custom hostnames, the address Let's Encrypt writes to about their certificates, and the key of a separate Cloudflare token when the platform domain is in another Cloudflare zone from Infrared's own address. |
spec.edge | How traffic from outside reaches Infrared and its zones: traefik (the default, through Traefik Ingresses) or gateway (one shared Gateway, run by Envoy Gateway). |
spec.models | tiers maps each model tier (frontier, balanced, fast) to a model ID. Empty tiers use claude-opus-5-5, claude-sonnet-5-5 and claude-haiku-4-5-20251001. prices[] sets model, inputUSD, outputUSD, cacheReadUSD and cacheWriteUSD per million tokens for cost estimates; leave it empty to use the built-in list prices. See Models and costs. |
spec.backup | Where backups go and how they are made. destination holds provider (linode, s3 or gcs), bucket, endpoint, region, prefix (default: the management cluster's name) and credentials. Credentials are kind: accessKey with a secretRef to the Secret that holds the key, for linode and s3, or kind: serviceAccount for gcs, which uses the identity of whatever runs and keeps nothing in a Secret. The key itself is never here. Then schedule (default 5 * * * *, UTC), mirror.schedule (default 17 * * * *), retention (default 7d), recipients[] (age public keys; without one no backup is made) and postgres.archive (not with gcs). Set it in Settings → Backups. See Back up and restore. |
spec.summaryVideos.enabled | Whether this install makes summary videos, switched in Settings → Install features. Off or unset, no org can make one. See Summary videos. |
spec.signIn.google.allowedDomains | The Google Workspace domains whose people may sign in with Google, such as example.com. A sign-in needs both the ID token's hd claim and the email address's domain on the list. Each entry is lower-case with at least one dot and no wildcard. Empty means nobody signs in with Google. Platform admins change it in Settings → Sign-in, signed in with Google or as the root user. The Google OAuth client, and whether the root user's password still signs in, are chart values, not fields here. See Sign in with Google. |
spec.signIn.google.groupRoles | since and by. The API sets it once, when a platform-admin access group of the platform org first has a Workspace group that holds an active person. From then on, Google sign-ins take their roles from Workspace groups, and an allowed domain no longer makes everyone a platform admin. Infrared never clears it. See What a Google session can do. |
spec.signIn.google.selfSignUp | Opens Sign in with Google to anyone with a verified Google account, as a hosted control plane does. enabled gives a first sign-in that holds no role an org of its own on the install's Gitea. products, people, newTeams and publicEnvironments are the limits that org starts with (see the Organization's spec.limits). A platform admin sets it in Settings → Sign-in. It is refused on an install without Gitea. |
status.phase | AwaitingToken, AwaitingAdmin, AwaitingOrg, AwaitingCluster, AwaitingGitProvider, AwaitingGitopsRepo, Syncing or Ready. |
status.version | The Infrared control plane version. |
status.backup | What the operator last saw of backups: lastBackup, lastBackupAt, lastMirrorRun, lastPoint, lastPointAt and message. Stamps are UTC, such as 20261006T010500Z. The condition BackupsHealthy says whether they are on time. |
status.postgresServerName | The name the platform's Postgres archives under in the backup bucket. Chosen once and never changed. |
Organization
An org: the tenancy and RBAC boundary. A name is at most 56 characters, so ir-org-<name> fits a namespace, and a few names are reserved, such as platform, infrared, argocd, builds, default and new.
| Field | Meaning |
|---|---|
spec.displayName | The name people see in the UI. |
spec.platform | True for the org that administers the control plane. |
spec.clusterAllowlist | The workload clusters this org may place zones on. A platform admin sets it. See Workload clusters. |
spec.clusterSelfService | Lets the org's admins register and build workload clusters of their own, by kubeconfig or through one of the org's cloud accounts. A platform admin sets it; off by default. See Workload clusters. |
spec.accessGroups[] | Who holds which role in the org, one entry per access group. name is a DNS label. role is platform-admin (platform org only), org-admin, member or viewer. googleGroup is a Google Workspace group's address in an allowed domain; its people hold the role when they sign in with Google. members[] are GitHub logins: people who sign in with GitHub, and, on an access group with no googleGroup, people who sign in with Google and linked that login. emails[] are people by their Google address, for people with no Workspace group or linked login, such as an org made by self-service sign-up; adding an address is the invitation. githubTeam is the slug of a GitHub team in the org's GitHub organization that infrared-operator keeps in step, one per access group. description is free text. See Access groups. |
spec.teams[] | Deprecated: the old name of spec.accessGroups. It is read only while spec.accessGroups is empty, and you can't set both. Move its entries to spec.accessGroups. |
spec.limits | Bounds on what the org may hold, beyond the license's install-wide limits. products caps its Products, people caps the people it names (in its access groups, and its Humans), newTeams caps the Teams it may make beyond the catalog's default Teams, and publicEnvironments: false stops it making an environment public. Zero or unset means no cap, except that newTeams: 0 means none. Self-service sign-up sets them; a platform admin may change them, and may go past them. |
spec.scheduling | enabled turns on the cron triggers of the org's AgentWorkflows (off when absent). timeZone, such as America/New_York, is the zone schedules are read in; empty means UTC. See Triggers and scheduling. |
spec.modelTiers | The org's own tier-to-model mapping: frontier, balanced, fast. Empty fields use the Installation's. See Models and costs. |
spec.summaryVideos | enabled gives each Change that finishes or stops a short summary video. monthlyCapUSD stops making them once the month's videos cost that much (default 5). timeZone is the zone a video's greeting uses (default America/New_York). See Summary videos. |
spec.slack | The org's Slack workspaces and where Infrared posts. workspaces[] each have teamID, teamName, tokenSecret (the Secret in the org's namespace with the bot token) and who connected it. destinations[] each have name, teamID, channelID, channelName and kinds[], what goes there (summary for summary videos; empty means everything). Older single-workspace fields (teamID, channelID and the like) are still read until the org's Slack settings are next saved. See Slack. |
spec.buildRegistry | The Registry, in the org's namespace, that its Products build into from their next build. Empty means the install's default registry. See The build registry. |
status.namespace | The org's namespace, ir-org-<name>. |
status.accessGroups[] | For each access group, by name, infrared-operator's last sync of its GitHub team, under githubTeam: slug, url, members[] on GitHub after the sync, skipped[] (each login it didn't add or remove, with the reason), syncedAt, and message when the sync couldn't run. See GitHub teams. |
A non-platform org carries the finalizer infrared.darkshift.io/org-cleanup. When you delete the org, it holds the Organization until Infrared has removed the org's Argo CD objects and its builds namespace.
Cluster
A management or workload cluster.
| Field | Meaning |
|---|---|
spec.type | management or workload. |
spec.flavor | k3s or eks. Selects the distribution's own components. |
spec.provider, spec.region | aws, gcp, linode or local, and the provider's region. |
spec.template.module, spec.template.version | The cluster template (a module in infrared-iac-modules, gcp/gke-cluster or aws/eks-cluster) and its tag. |
spec.server | The API server URL Argo CD uses. Empty means the kubeconfig's server, or in-cluster. |
spec.connection | How Infrared and Argo CD reach a workload cluster. inCluster: true places its zones on the management cluster itself. kubeconfigSecretRef (name, key) names a kubeconfig in namespace infrared with a token or client-certificate user. When you give the API a kubeconfig, it stores it as cluster-<name>-kubeconfig, key kubeconfig. See Workload clusters. |
spec.provision | Runs the cluster template with OpenTofu. action is plan (the default), apply, which creates billable cloud resources, or destroy, which lifts the template's guards and deletes what it built. source defaults to the template's module in infrared-iac-modules at template.version. variables are the module's inputs. image defaults to ghcr.io/opentofu/opentofu:1.10. Without a cloud account, the Job's credentials are the keys of the Secret cluster-<name>-credentials in namespace infrared, such as AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_REGION. credentialsSecretRef is deprecated and ignored. See Build a cluster with OpenTofu. |
spec.provision.cloudAccount | A Verified CloudAccount of the platform org, for the same cloud as spec.provider. Before each OpenTofu run, Infrared mints its short-lived credentials as cluster-<name>-credentials and deletes them when the Job ends. See Cloud accounts and registries. |
spec.owner | The org a workload cluster belongs to: org and registeredBy (org when one of the org's admins registered it, so its registry lives in the org's gitops repo, or platform). Empty means the platform's. An org's cluster is reached by kubeconfig or built through the org's own cloud accounts, and the org may place zones on it without the cluster allowlist. It can't change. |
status.kubernetesVersion, status.nodes | The version and node count Infrared last saw. |
status.detected | True for the cluster Infrared found itself running on. |
status.argoServer, status.argoSecret | The server URL Argo CD Applications use for the cluster, and the Argo CD cluster Secret Infrared wrote (cluster-<name> in argocd; none for inCluster). |
status.gitopsPath | The gitops repo folder whose Applications run on the cluster, registry/clusters/<name>/components. |
status.provision | The last OpenTofu Job: job (in namespace infrared), action, phase (Waiting for the credentials Secret, Running, Succeeded or Failed), message, and the Cluster generation it ran for. |
status.inventory | What deleting the cluster would remove, read every ten minutes while it is reachable: whether Infrared built it, an hourlyCost estimate, volumes[], loadBalancers[] and applications[]. |
status.deletion | Once you delete the cluster: its phase, its mode (destroy for a cluster Infrared built, disconnect for one it only registered), whether volumes are backed up first, its steps[] (each Pending, Running, Waiting, Stuck, Done, Skipped, Failed or Forced), the volume snapshots[], and leaks[], anything it may have left behind. See Delete a cluster. |
status.conditions | Besides the common ones, Connected (Infrared reaches the API server) and Registered (Argo CD can deploy to it and the gitops repo has its app-of-apps). |
A workload Cluster carries the finalizer infrared.darkshift.io/cluster-deletion until its deletion has run. The API sets infrared.darkshift.io/delete-backup (false skips the volume backup), infrared.darkshift.io/delete-by and, to move a stuck step on, infrared.darkshift.io/delete-force.
BreakGlass
The root user: the install's first platform admin, a break-glass account whose password lives only in a vault outside Infrared. There is one object, named root, and only the API writes it. Nothing in it is the password. See Break glass.
| Field | Meaning |
|---|---|
spec.email | The root user's sign-in address. |
spec.passwordHash | The bcrypt hash of the root password. Nothing else of the password is kept. |
spec.vaults[] | Up to 5 links to the vaults that hold the password: name, as people know the vault, and url (https://). Links only, never a secret. |
spec.item | The vault item's name. |
spec.holdersGroup | The Workspace group of the people who should be able to open the vault. It is a record only; the vault decides who opens it. |
status.passwordSetAt, status.passwordSetBy | When the password was last set, and by whom: a platform admin's address, setup or migration. A root session signed in before then is signed out. |
status.rotations[] | The password's last 20 changes, newest first: at and by. |
status.uses[] | The root user's last 100 uses, newest first: at, method (password, sign-in-link or token), client (the caller's address), host (the address Infrared was opened at), userAgent and detail. |
status.useCount, status.lastUsedAt | How many uses there have been in all, and when the last one was. |
status.refusals | count and lastAt of refused password sign-ins, written at most once a minute. |
status.migratedFrom, status.generatedPasswordRemoved | On an install set up before this record existed: where the hash was copied from, and whether the API removed a generated plain-text password, in which case rotate the password. |
User
A person who signs in with Google, as Infrared knows them. The API makes it at their first Sign in with Google and names it google-<subject>, after the Google account's stable ID. See Linked accounts.
| Field | Meaning |
|---|---|
spec.google.subject, spec.google.email | The Google account's stable ID (the ID token's sub claim) and its address, as last read at sign-in. |
spec.displayName | The name Google gives the person. |
spec.links[] | The person's linked git accounts, one per git connector, at most 20: connector, kind (github, gitlab or gitea), id (the forge's numeric user ID), login (as last read from the forge) and linkedAt. Each link also sets the label links.infrared.darkshift.io/<connector>: <id>, so an account belongs to one person. |
status.lastSignInAt | The person's last Sign in with Google. |
status.directory | What Google Workspace's directory said of the person: checkedAt, suspended, and groups[], the mapped Workspace groups they are in, nested groups included. After 10 minutes it no longer counts. |
GitConnector
A forge people link their git accounts on: GitHub, GitLab or Gitea, at an address. Named by a DNS label; the API writes it. See Git connectors.
| Field | Meaning |
|---|---|
spec.kind | github, gitlab or gitea. |
spec.displayName | What people see, as in Link GitHub. |
spec.baseURL | The forge's https:// address in a browser, such as https://github.com or https://git.example.com. |
spec.githubApp.organization | Link through the OAuth client of that Infrared org's GitHub App (kind github only). |
spec.oauth.clientID, spec.oauth.clientSecretRef | An OAuth application made on the forge for Infrared. The secret is the key <connector>.client-secret of the Secret infrared-git-connectors in Infrared's namespace. A connector has exactly one of githubApp and oauth. |
spec.managed | True when Infrared registered the OAuth application on its own Gitea. |
status.conditions | Ready: the last check found the forge accepting the client. |
status.checkedAt | When the connector was last checked. |
GitProvider
Connects an org to its forge: GitHub through a GitHub App (github-app), or the Gitea the chart runs (gitea).
| Field | Meaning |
|---|---|
spec.type | github-app or gitea. |
spec.owner | The GitHub organization (or Gitea owner) Infrared manages. |
spec.github.appID, spec.github.slug | The GitHub App. |
spec.github.installationID | Set once the App is installed on the owner. |
spec.github.privateKeySecretRef | The Secret key that holds the App's PEM private key. |
spec.github.webhookSecretRef | The Secret key that holds the webhook secret. Optional. |
spec.github.apiURL | Overrides https://api.github.com, for GitHub Enterprise Server. |
spec.gitea | For gitea: url (the Gitea server as the cluster reaches it), user (the Gitea user Infrared acts as, such as ir-acme) and secretRef, the Secret with its username, password, token and read-token. |
status.installationVerified, status.lastVerifiedTime | Whether and when the App last minted an installation token. |
GitopsRepo
An org's gitops repo, which Infrared creates, hydrates and bootstraps.
| Field | Meaning |
|---|---|
spec.providerRef | The GitProvider that owns the repo. |
spec.name, spec.visibility, spec.defaultBranch | Default gitops, private (or internal, public) and main. |
spec.template.repo, spec.template.version | The gitops template (default https://github.com/darkshiftio/infrared-gitops-template) and the tag or full commit it is hydrated from. |
spec.cluster, spec.clusterFlavor | The management cluster the registry bootstraps, and its flavor (default k3s). |
spec.bootstrap | Apply Argo CD and the root Application after hydration. Default true. |
spec.mode | management (the default) for the platform org's repo, which runs the whole management cluster. org for any other org's repo, which holds only that org's Products: Infrared applies its Applications itself, each inside the org's own AppProject (org-<org>), and never installs Argo CD from it. |
spec.infraredSubchart | When set, the infrared Application installs an umbrella chart that wraps Infrared's chart under this name, such as infrared-core, and every render nests its values there. |
status.phase | Pending, Created, Hydrated, Bootstrapped or Synced. |
status.url, status.commit, status.hydratedVersion | The repo's URL, the last hydration commit and the template version used. |
status.hydratedChartVersion, status.hydratedByChartVersion | The Infrared chart version the last hydration rendered, and the chart version of the operator that ran it. When either moves, the operator hydrates again. |
status.bootstrappedCommit | The hydration commit whose Argo CD install and registry Application were last applied. Bootstrap runs again only when status.commit moves past it. |
status.restorePoint | The backup stamp a restore in progress came from, while the hydration renders a restore. |
status.components[] | Each component of the template as the last hydration rendered it: name, rendered, and for one left out, reason (Disabled or NotApplicable) and message. |
status.waves[] | Per sync wave, each Application's sync (Synced, OutOfSync, Unknown) and health (Healthy, Progressing, Degraded, Suspended, Missing, Unknown). |
Product
The unit Infrared builds, deploys and manages change for. A few names are reserved, because a Product's zones are the namespaces <name>-*: among them argocd, builds, infrared, kube, kpack and monitoring. The condition NameAllowed says whether the name may be used.
| Field | Meaning |
|---|---|
spec.displayName, spec.description | Shown in the UI. |
spec.owner | The Product's product owner: a Human in the org, by name. |
spec.providerRef | The forge the Product's repos are on, github or gitea, for an org with both. Empty means the org's forge. It can't change once set. |
spec.repos[] | The repos in the Product, each an app that is built and deployed: owner (empty means the GitProvider's owner) and name. At least one. A repo belongs to one Product. |
spec.currentRelease | The release in progress, such as 2.4. |
spec.logo | repo (default: the first repo) and path (default: found where logos usually live). See Products. |
spec.delivery | How deployments ship. Without it, Infrared starts no deployments for the Product. strategy is isolated (the default) or umbrella, one version of the umbrella chart with every repo's image; see Deliver several repos as one chart. repo is the repo deployed and tagged vX.Y.Z (empty means the first; with umbrella delivery, the repo that runs from the chart itself). buildImage is the kpack Image in namespace builds (empty means the Product's name). scaffold has kind (static, node, go, or auto for a new repo whose code is still to come) and root for a static site; Infrared then writes the build, a generic web chart and the zones' files into the gitops repo and starts the first deployment. zones[] lists the zones in promotion order. See Deliver a single app. |
spec.delivery.zones[] | name (also its namespace), environment (pre-release, the default, or release), approval (auto or human; empty means auto for pre-release and human for release), preview (an address under the platform domain, behind sign-in), public (open it to anyone; org admins only), replicas (0 to 20), resources (cpu and memory per pod) and storage[] (up to 8 volumes: name, size, mountPath). The rows below cover addresses, checks, variables and placement. See Environments and instances. |
spec.delivery.zones[].addresses[], primaryAddress | Up to 10 more addresses: domain, name (empty for the domain itself) and redirect (send visitors to the zone's first address that doesn't redirect). primaryAddress is the address Infrared opens the zone at: custom (the default, the first non-redirecting address while it serves) or automatic (its address on the platform domain). See Domains and addresses. |
spec.delivery.zones[].verify | A smoke check after Argo CD reports the zone Healthy: url, expectStatus (default 200), contains and soak (default 2m). |
spec.delivery.zones[].guard | The release guard. hold defaults to 5m (0s for none). rollback is rollback (put back what the zone ran before when it fails the guard) or notify (report it and keep the new version); notify applies when it is unset, and the API sets rollback on every zone it adds. checks[] adds up to 10 more checks shaped like verify. sloBurn is the error budget check, on when unset: threshold is the burn rate that fails the zone (default "14.4", "0" turns it off), and slos[] names the SLOs it reads (default all of the zone's). |
spec.delivery.zones[].env[], secretEnv[] | The zone's environment variables. Plain ones (name, value) go into its values file in the gitops repo. Secret ones list only their name: the values live in the Secret <product>-<zone>-env in the org's namespace, which Infrared copies into the zone as <product>-env. See Environment variables. |
spec.delivery.zones[].cluster, valuesPath, applicationPath | Where the zone runs (empty means the gitops repo's management cluster; otherwise a cluster on the org's allowlist or one it owns), and where its files are, by default products/<product>/zones/<zone>/values.yaml and registry/clusters/<cluster>/components/product-<zone>.yaml. |
spec.delivery.zones[].target | Empty for a zone that is one of the Product's namespaces, or controlPlane: the install's own control plane. A deployment then upgrades the control plane to the umbrella chart's version behind the upgrade guard, a Job running the operator that was there before, which rolls a bad upgrade back. Only the platform org may hold such a zone, as the Product's only zone, with strategy: umbrella, components and charts. controlPlane holds application (the Argo CD Application that installs the chart, default infrared) and guardTimeout (default 15m). |
spec.delivery.components[], spec.delivery.charts | For a Product with a control plane zone. Each component has name, repo, buildImage (or none, to carry its pin), valuesKey and repository. charts says where a release goes: releaseRegistry (images, copied by digest and tagged with the version), chartRegistry (the umbrella chart, pushed to OCI), subchart (name, repo, path), firstVersion, historyFrom and buildsNamespace. |
spec.slos[] | Service level objectives, measured per zone: name, description, objective (a percent, such as 99.5), window (default 168h), zones[] (empty means every delivery zone) and one indicator. The indicator is availability (metric, errors (default code=~"5.."), filter), latency (histogram, threshold in seconds, filter), uptime (the share of minutes with a ready pod, from kube-state-metrics; optional deployment), or, on the gateway edge, edgeErrors or edgeLatency (thresholdMS), read from Envoy. Every Product with zones gets an uptime SLO (99.5%, 168h), and on the gateway edge also edge-errors (99.5%) and edge-latency (99% within one second), unless it defines its own by those names. See SLOs. |
spec.statusPage | public serves the status page to anyone at /status/<org>/<product>. zones[] picks the zones it shows; empty means the Production zones. See Status page. |
spec.humanApprovals | Whether people approve the Product's Changes and deployments. false makes triage, human approval and promotions to approval zones approve themselves. A reviewer's BLOCK, a failed step and a dead-lettered step still wait for a person. Omitted means true. See Turn human approvals off. |
spec.slack | The Product's own Slack destinations: mode (add, the default, adds them to the org's; replace uses them alone) and destinations[], shaped like the org's. Omitted means the org's. See Destinations per Product. |
spec.umbrella | Where a Product with more than one repo, or with umbrella delivery, keeps its umbrella chart: repo (the org's charts repo, default charts), chart (default: the Product's name) and disabled (refused with umbrella delivery). |
spec.kind, spec.platform | Deprecated. They described Infrared itself as a platform Product. A Product with umbrella delivery and a controlPlane zone does the same now, and converting one clears both fields. |
status.logo | repo, path, sha, contentType, bytes, source (detected or uploaded), syncedAt, pending and message. Cached in the ConfigMap <product>-logo. |
status.zones[] | What each zone runs, as the deployments that promoted to it recorded: name, version, image (the pin), release, chart (the umbrella chart's tag, with umbrella delivery) and promotedAt. Then addresses[], what each address does now, checked every few minutes: host, dns, certificate (Ready, Pending or Failed), serving (the HTTP status it answered), records[] to add at your DNS provider, message and checkedAt. And rollout, which follows the zone's latest address or access change until it is live: commit, summary, at, phase (committed, syncing, certificate or live) and liveAt. |
status.zoneFiles | Whether every zone has its values file and Application in the gitops repo: ready, message, scaffolded[] (zones whose files Infrared copied from another zone), zones[] (every zone whose files Infrared has seen, with name, values, application, applicationName, namespace and cluster), removing[], and envNotice, which says why the chart can't take environment variables yet. |
status.observability | The VMRule that holds the SLOs' recording and alerting rules: rules, ready, message, and edgeZones[], the zones the edge SLOs read. |
status.teams[] | The Teams that work on the Product: name and responsibility (own or contribute). |
status.umbrella, status.platform | The state of the Product's umbrella chart, and for a Product with a control plane zone, its components, their builds and the version running. |
When you take a zone out of spec.delivery.zones, Infrared removes it. It deletes the zone's files from the gitops repo with a pull request it merges, Argo CD deletes what the zone's Application deployed, and Infrared deletes the zone's namespace on the management cluster. Deleting a Product does the same for every zone, its build and its chart. The finalizer infrared.darkshift.io/zones holds the Product until that is done, and status.zoneFiles.message says what it is waiting for.
AgentRole
A job an agent performs. See AgentRoles, AgentWorkflows and AgentWorkflowRuns.
| Field | Meaning |
|---|---|
spec.displayName, spec.summary | The name, and a one-sentence summary of at most 280 characters. |
spec.category | architect, change-review, scheduled or builder. |
spec.mission | The outcome the role is accountable for. |
spec.responsibilities[] | Its steps, in order. |
spec.triggers[] | type (adhoc, onChange, cron or event), schedule, event, description, and optional filters labels[], paths[] (globs) and branches[]. |
spec.inputs[] | source and description. |
spec.outputs[] | What the role leaves behind. |
spec.evidence[] | kind (screenshot, video, report, log, comment, diff, sarif, metric, document, trace or sbom), description and required. |
spec.successCriteria[] | Statements you can check, which must all hold. |
spec.guardrails[] | What the role must never do. |
spec.permissions | allowedTools, deniedTools, git, cluster, network (none, allowlist, the default, or open), egressAllowlist, mayMerge and publish. Deny wins over allow. egressAllowlist may contain $(ZONE_HOSTS), which the runner expands to the Product's zone hostnames. publish lets the role's steps push images and charts to the install's registry under <org>/<product>; the agent never sees the key. |
spec.escalation | when[], to (a GitHub team or user handle) and after (a duration such as 30m). |
spec.opinions[] | name, title, guidance, origin (catalog, org or tailored) and enabled. Omitted means on; false keeps the opinion, but the agent doesn't receive it. |
spec.verdicts[] | The verdicts a step may end with, such as VERIFIED, MERGE WITH FOLLOW-UPS or BLOCK. Every step ends with exactly one. |
spec.instructions | Markdown added to the role's prompt for the org. |
spec.skills[], spec.mcpServers[] | The skills and MCP servers the org configured for the role, by name. |
spec.model | providerRef, model (a model ID, which wins over tier), tier (frontier, balanced or fast; omitted means frontier), reason, maxBudgetUSD (a decimal string) and maxTurns. See Models and costs. |
spec.enabled | Whether the role runs. An AgentWorkflow step that uses a disabled role is Skipped, and the steps that need it continue. |
spec.origin | catalog (the catalog version it was seeded from), tailored and tailoredFrom[]. |
status.stats | runs7d, succeeded7d, medianTokens and lastRunTime. |
status.differsFromCatalog | True when the org edited the role after it was seeded. |
AgentWorkflow
Orders AgentRoles and gates into a workflow you can run again and again.
| Field | Meaning |
|---|---|
spec.displayName, spec.description | Shown in the UI. |
spec.triggers[] | Shaped like an AgentRole's triggers. |
spec.steps[] | name, type (agentRole, human, auto, ci or promote), agentRole, zone, required, onFailure (deadLetter, fail or continue), maxAttempts, needs[], independent, when, approvers[], minApprovals, timeout and description. Empty needs means the previous step, and independent: true starts the step with the workflow. approvers, minApprovals (default 1) and timeout set up human gates; timeout works on any step. A step whose AgentRole is switched off is Skipped. |
spec.steps[].when | A condition such as change.author in [human], agentRole.enabled, label:security or pullRequest.conflicted (true when the Change's pull request can't merge cleanly into its base), combined with && and negated with !. A merge step that meets conflicts goes back to the latest pullRequest.conflicted step, up to 3 rounds. |
spec.steps[].mode | What an agentRole step works on: build, review, issue, resolve (apply a conflicted Change again on its base branch) or report (no Change; read and report). Empty means build for the first agentRole step and review after it, or report in a run without an issue or pull request. |
spec.steps[].model, spec.steps[].maxBudgetUSD | Override the AgentRole's model for this step (a tier or a model ID), and cap what one attempt of it may spend. See Models and costs. |
spec.steps[].returnTo, spec.steps[].maxReturns | An earlier agentRole step the run goes back to when this step ends with CODE CHANGE NEEDED: QA or a reviewer found that the builder must fix the code. The builder fixes it on the same branch and every step from it runs again. maxReturns (1 to 5, default 2) bounds how often; after that the step fails and onFailure hands the Change to a person. |
spec.steps[].deliver | Where a report step's output goes: issue (an issue on the Product's backlog, the default) or slack (a draft to the org's Slack; nothing is opened on the forge). |
spec.deadLetter | to (default: the human reviewer) and notify[] channels, such as slack:#checkout-changes. |
spec.maxConcurrency | How many runs may go at once. Default 3. |
spec.budget | Caps the weekly spend of the workflow's runs: group (every AgentWorkflow in the org with the same group shares the budget), weeklyUSD, and scheduled, which runs its cron triggers even while the org's scheduling is off, so the budget alone bounds the spend. |
spec.limits | The circuit breaker: maxRunsPerDay per Product (default 100) and maxConsecutiveFailures (default 10). Past either, the operator sets the condition Tripped and starts no run of the workflow until you change its spec. |
spec.enabled, spec.origin | As for an AgentRole. |
status.schedule, status.nextScheduledAt, status.lastScheduledAt | For a workflow with a cron trigger: in plain words, whether and when it runs on its own, and when it next and last started runs. See Triggers and scheduling. |
AgentWorkflowRun
One run of an AgentWorkflow. The operator runs each agentRole step as a runner Job, waits at human gates for approval, and merges the pull request at the end.
| Field | Meaning |
|---|---|
spec.workflowRef, spec.productRef | The AgentWorkflow and the Product. |
spec.change | repo, issue (such as checkout-web#212) and pullRequest. |
spec.trigger | What started the run, such as onChange:pull_request.opened:<login>, event:issue.opened:<login>, event:release.cut:<product> <version>, cron:<schedule> or adhoc:<user>. |
spec.triggerKey | The event the run answers, so one event starts one run. A run whose key an earlier run of the same workflow already carries ends Skipped before it starts. Infrared sets it. |
spec.guidance[] | What people told steps when they retried them, oldest first: step, by, text and at. Each agentRole step sees its own entries in its prompt. |
status.phase | Queued, Running, DeadLettered, AwaitingApproval, Succeeded, Failed, Cancelled or Skipped. |
status.steps[] | Per step: name, phase, type, agentRole, verdict, attempts, startedAt, finishedAt, model and modelTier (what the step was started with), usage (with byModel[], tokens and cost per model) and attemptUsage[] (each attempt's), evidence[] (with a result per success criterion), questions[], published[], decidedBy, rounds[] and message. questions are what the agent needs a person to answer, each with a suggestion; retry the step with guidance to answer them. published lists the images and charts the step pushed. decidedBy is who approved, rejected or handed off a human step. rounds keeps the step's earlier results each time a later step sent the run back to it. |
status.usage | Input, output, cache-read and cache-write tokens, costUSD, byModel[], turns and durationMs for the whole run. |
status.pullRequest, status.branch, status.mergeCommit | The pull request the build step opened, the branch the agents commit to (infrared/<run>), and the commit the merge created. |
status.release | The deployment (its Release) the run's promote steps created for the merge. |
status.conflictRounds, status.returnRounds | How often the run went back to resolve merge conflicts, and how often a step sent it back to the builder with CODE CHANGE NEEDED. |
status.message | What the run is doing or waiting for, in plain words. |
status.startedAt, status.finishedAt | When the run started and ended. |
You steer a run with annotations, which the API sets for you. infrared.darkshift.io/approve.<step> and infrared.darkshift.io/reject.<step> decide a human step. infrared.darkshift.io/retry.<step> runs a DeadLettered or Failed step, and every step after it, again. infrared.darkshift.io/cancel, with infrared.darkshift.io/cancel-reason, cancels the run.
Release
A deployment: one commit of a Product on its way to every zone. The kind keeps the name Release, but the UI and ir deployment call it a deployment. See Deliver a single app and Deployments.
| Field | Meaning |
|---|---|
spec.productRef | The Product. |
spec.version, spec.commit | The version to tag (empty means the next after the newest vX.Y.Z tag) and the commit (empty means the default branch's head). |
spec.runRef | The AgentWorkflowRun whose Change the deployment ships. |
spec.pushes[], spec.notBefore | The pushes to a repo's default branch the deployment ships, oldest first: repo, commit, by, at and commits. The deployment stays Pending until notBefore, so pushes close together ship as one. |
spec.image.fromStep | Deploy an image a step published (run, step, and ref when the step published more than one) instead of kpack's build of the commit. |
spec.recorded | Marks a release made outside Infrared, by hand. Infrared fills in its status from the chart's tag and never acts on it. |
spec.notes | The forge release's notes, on deployments from before releases were cut on their own. A ReleaseCut holds the notes now. |
status.phase | Pending, Building, Tagged, Promoting, AwaitingApproval, Released (Deployed in the UI) or Failed. |
status.version, status.commit, status.repo, status.image, status.build, status.previousVersion | What the deployment resolved and tagged: the version, the commit, the delivery repo, the image pin, the kpack Build of the commit (set as soon as kpack starts it; the image is built once status.image is set) and the newest version tag before it. |
status.releaseURL, status.forgeReleaseAt, status.latestAt | The forge release on the deployment's tag (an umbrella deployment keeps its chart's address here), when it was made, and when Infrared marked it as the repo's latest, once the deployment ran Healthy in every zone. |
status.buildSteps[], status.buildPod | kpack's steps in the order they run, each with name (prepare, analyze, detect, restore, build, export and completion for a full build; rebase and completion for a rebase), phase (Waiting, Running, Succeeded or Failed), startedAt, finishedAt and message (why a step failed, with its exit code, or why a waiting step's container can't start). buildPod is the build's pod in the org's builds namespace, with a container per step, which holds the steps' logs while kpack keeps it. |
status.message, status.attempts, status.retriedBy | What the deployment is doing or waiting for, how many times it has run (1, plus one per retry), and who asked for the latest retry. |
status.startedAt, status.builtAt, status.taggedAt, status.finishedAt | When the deployment started, when its build was ready and its digest tagged, when the git tag was made, and when it finished. |
status.changes[] | The commits the deployment ships, oldest first, from the previous version to its commit, read once when it is tagged, at most 250: each commit, subject, kind (feature, fix, breaking or other, from its conventional commit subject), pullRequest, author (a login on the forge) and, for an umbrella deployment, repo. |
status.zones[] | Per zone: environment, approval, phase (Pending, AwaitingApproval, Promoting, Syncing, Verifying, Holding, Healthy, Failed, RollingBack or RolledBack), the promotion pullRequest and pullRequestURL, approvedBy, message, startedAt, healthyAt, and for zones with a smoke check verifiedAt and verifyAttempts. previous is what the zone ran before (version, image, release, and chart with umbrella delivery), which a rollback puts back. rolledBackTo and rollback (pullRequest, pullRequestURL, startedAt, finishedAt) record a rollback. |
status.zones[].guard | What the release guard found. result is Watching, Passed or Failed. Then rollback, hold, holdStartedAt, unhealthySince, wentAheadBy and wentAheadAt (who ended the hold with Go now, by name, never by email address, and when), passedAt, failedAt and reason. checks[] gives each check's url, status, passed, attempts, message and at. slos[] gives each SLO's error budget reading: name, objective, window, errorRatio, baseline (the hour before the deployment), burnRate, threshold, passed, message and at. |
status.rolledBackTo, status.components[], status.chart, status.guard | The version a zone (or the control plane) was rolled back to. For an umbrella deployment, each component's image and commit and whether it changed, and the chart it published. For a control plane zone, the upgrade guard's Job. |
The API sets these annotations for you. infrared.darkshift.io/promote.<zone> approves promoting a deployment to a zone. infrared.darkshift.io/go-now.<zone> ends the release guard's hold in a zone now; its value is who pressed Go now, and the operator honours it once, only while the zone is Holding with a hold left and Synced and Healthy, then records it in the zone's guard and removes it. infrared.darkshift.io/retry on a Failed deployment starts it again from where it failed. infrared.darkshift.io/started-by records who started a deployment by hand; the operator ignores it.
ReleaseCut
A release, as people read it: the deployments of a Product that reached production since the last release, under one version, written up twice, as notes for engineers and a post for everyone else. Deployments only bump the patch; a cut takes the next minor or major. Infrared tags the commit and the image running in production with the version, creates the forge release with the notes, marks it latest, and sends the release.cut event once. Named <product>-<major>-<minor>-<patch>, such as zippy-1-7-0. An org-admin cuts one from the Product's Releases tab or with ir release cut. See Releases.
| Field | Meaning |
|---|---|
spec.productRef | The Product. |
spec.version | The release's version. For a minor or major cut, vX.Y.0; for a track cut, the version in production itself. It can't change. |
spec.bump | minor, major, or track, which announces the version already in production as its major.minor track and writes the title and notes onto the forge release its deployment made. |
spec.deployment | The deployment (Release) running in production when the cut was made. The cut tags its commit and image digest, so the release is exactly what runs. |
spec.covers[] | The deployments the release covers, oldest first: those that reached production after the last cut. spec.deployment is the last. |
spec.title, spec.notes, spec.post | The title, the release notes for engineers (Markdown, the forge release's body), and the post for everyone else (Markdown). |
spec.cutBy | Who cut it, by name, never by email address. |
status.phase | Pending, Tagging, Publishing, Released or Failed. |
status.repo, status.commit, status.image, status.imageDigest | The delivery repo, and the commit and image the cut tags. |
status.tag, status.taggedAt, status.imageTaggedAt | The git tag the cut made, and when it tagged the commit and the image. |
status.releaseURL | The forge release, created on the tag with the notes and marked latest. |
status.cutDispatched, status.cutRuns[], status.cutAt | Whether release.cut was sent, the AgentWorkflowRuns it started (one per enabled AgentWorkflow with that event trigger), and when the cut was Released. |
status.message | What the cut is doing, or why it failed, in plain words. |
Every field of the spec is set when the release is cut and never changed. Each step of the cut is skipped once its status field is set, so a pass that fails part way never repeats a step.
Team
A Team is where people and agents work together under one discipline. Workforce → Teams shows each one. A Team grants nothing, and it is not an access group: roles come only from access groups. See Workforce.
| Field | Meaning |
|---|---|
spec.displayName | The Team's name as people see it, such as Site reliability. |
spec.discipline | Its discipline, such as engineering, sre or qa. |
spec.charter | What the Team is for, in words. |
spec.manager | The Human who manages the Team, by name. |
spec.humans[] | The Team's Humans, by name, up to 200. |
spec.agents[] | The org's AgentRoles that work on the Team, by name, up to 100. |
spec.products[] | The Products the Team works on: product and responsibility, own or contribute. A Product has at most one owning Team. |
spec.policyTemplate | The access the Team's members should have by default: a description and grants[], each resource (kubernetes, cloud, forge, observability or other), scope and access (read, write or admin). Infrared stores and shows it, and never enforces it. |
spec.context.path | The Team's own folder in the org's gitops repo, for its charter, history and daily records. Empty means teams/<name>/. |
spec.dailyStatus | Has the team-manager AgentRole write each member's daily record and the Team's rollup once a day, through the daily-status AgentWorkflow, while the org's scheduling is on: enabled (off by default, since each run spends model tokens; only an org admin turns it on), hour (default 08:00) and timeZone (default: the org's scheduling time zone, else UTC). The rollup is kept at <context path>status/<date>.md. |
spec.character | How the Team looks and sounds: hue (infrared, violet, indigo, sky, teal, green, lime, amber, crimson or slate), which its AgentRoles wear; glyph, a Lucide icon name drawn on its mark; voice, a sentence or two on how it writes, which its AgentRoles are asked to follow; and sample, a line in that voice. Empty, the UI picks a colour from the name and a glyph from the discipline. |
status.missing[] | References that don't exist in the org, each as human/<name>, agentRole/<name> or product/<name>. |
status.policyTemplate.enforced | Always false. |
Human
A person in an org: their profile, their job role, their manager and how they look on Workforce → People. A Human grants nothing; access comes from access groups. It lives in the org's namespace. See Workforce.
| Field | Meaning |
|---|---|
spec.displayName | The name they go by. |
spec.jobRole | Their one job role, such as Site reliability engineer. |
spec.bio, spec.skills[], spec.pronouns | Free text about them, up to 50 skills, and their pronouns. |
spec.manager | The Human they report to, by name. Their reports are worked out from it. A Human can't be their own manager. |
spec.userRef | Their Infrared User, google-<subject>, once they have signed in. |
spec.handles[] | Who they are on each place the org works, such as github or slack: social (the place's name in the org) and handle (a login, a member ID or an address). Infrared uses a forge or Google handle to tie runs, pull requests and approvals to the person. |
spec.availability | timeZone and workingHours (start, end, days[]). |
spec.avatar | Their own drawn avatar: style, seed, and the parts, colors and options it is drawn from. |
status.accessGroups[] | The org's access groups that hold them, by a handle's login or by their User's Workspace groups. |
status.reports[] | The Humans whose manager they are. |
status.teams[] | The Teams that list them or have them as manager. |
status.ownedProducts[] | The Products whose product owner they are. |
Domain
A DNS name an org can put zone addresses under. The object's name is the domain with dots turned into dashes, such as acme-com. See Domains and addresses.
| Field | Meaning |
|---|---|
spec.name | The domain, such as acme.com, shop.acme.com or acme.example.com. |
spec.kind | external, a domain the org controls elsewhere, which it proves with a TXT record and points at Infrared with a CNAME or A record. Or managed, a subdomain directly under one of the Installation's spec.previews.managedRoots, whose DNS records Infrared creates. Some names under a managed root are reserved, such as www, api, status and admin. |
spec.shared | Lets every org put zone addresses under the domain. Only the platform org's domains can be shared. |
status.phase | Pending, Verified or Failed. |
status.token | The value of the ownership TXT record at _infrared.<domain>. |
status.records[] | The records to add at your DNS provider: type (TXT, CNAME or A), name, value and purpose. None for a managed domain. |
status.checks[] | The latest DNS checks: name (such as ownership, traffic and caa, or dns for a managed domain), ok, and message, which says what DNS answered and how to fix it. |
status.checkedAt, status.verifiedAt, status.message | When DNS was last checked, when the domain was first verified, and its state in plain words. |
The annotation infrared.darkshift.io/check asks Infrared to check DNS now. A managed Domain carries the finalizer infrared.darkshift.io/dns-records until Infrared has removed the DNS records it created.
Incident
Something wrong in a Product's zone that people are handling: opened by an alert or by a person, acknowledged, resolved, and kept with a timeline. See Alerts open incidents.
| Field | Meaning |
|---|---|
spec.productRef, spec.zone | The Product and the zone affected. |
spec.severity | critical, warning (the default) or info. |
spec.title, spec.description | What went wrong. |
spec.source | alert (opened by an alert) or manual (opened by a person). |
spec.alert | For an Incident an alert opened: name, fingerprint (the Alertmanager fingerprint, also the label infrared.darkshift.io/alert-fingerprint), labels, generatorURL and startsAt. |
status.phase | Open, Acknowledged or Resolved. |
status.openedAt, status.acknowledgedAt, status.acknowledgedBy, status.resolvedAt, status.resolvedBy | When it moved on, and who moved it. |
status.timeline[] | at, kind (opened, firing, alert-resolved, acknowledged, resolved, reopened or note), message and by. |
CloudAccount
A Google Cloud project or AWS account an org gives Infrared, reached through a role or an impersonated service account, never a key. Infrared checks it when you add it and every 24 hours after. See Cloud accounts and registries.
| Field | Meaning |
|---|---|
spec.displayName | How people see the account. |
spec.gcp | projectID, and the serviceAccount Infrared impersonates. |
spec.aws | accountID, the roleARN Infrared assumes, and the externalID its trust policy requires, if any. |
status.phase | Pending, Verified or Failed. |
status.checkedAt, status.verifiedAt | When the latest check finished, and when a check last reached the account. |
status.identity | What the cloud said Infrared acted as: the impersonated service account, or the assumed role's session ARN. |
status.message | What the cloud answered when the check failed. |
Registry
A container registry in one of the org's cloud accounts. Infrared keeps short-lived push and pull credentials for it and refreshes them before they expire.
| Field | Meaning |
|---|---|
spec.displayName | How people see the registry. |
spec.cloudAccount | The CloudAccount, in the same namespace, the registry is in. |
spec.ecr | Amazon ECR: region, and prefix, the path every Product's repository sits under. Infrared creates each Product's repository. |
spec.artifactRegistry | An Artifact Registry Docker repository: location and repository. |
status.phase | Pending, Ready or Failed. |
status.host, status.imagePrefix | The registry's host, and what each Product's image repository sits under. |
status.checkedAt, status.credentialsRefreshedAt, status.expiresAt | When Infrared last checked the registry, when it last got a credential, and when that credential stops working. |
status.message | Why the latest refresh failed. |