Home / Docs / Manifests

Manifests

In Yggdrasil everything is a versioned manifest — a workflow, an integration type, a deployed instance, a team, even the shape of the control plane itself. You describe the desired state as a declarative document, apply it, and the core keeps every version with history, checksum and the ability to roll back. It's real GitOps for operating your platform.

What a manifest is

A manifest is a YAML (or JSON) document with the same shape you know from Kubernetes — deliberately, because it's the pattern most teams already master. The envelope has four parts:

apiVersion
The version of the envelope schema. Today: yggdrasil.io/v1alpha1. The core accepts multiple apiVersions during deprecation windows.
kind
The resource type. It determines which validator the core applies to the spec (see the list below). It's normalized to lowercase before validation.
metadata
name (required), namespace (defaults to global), description, labels and active. The triple (kind, namespace, name) is the logical identity of the resource across all of its versions.
spec
The body specific to the kind (required). It's the only part whose format changes from one kind to another.

The model is declarative: you don't say how to get there, you say what the desired state is. The core reconciles. Unlike k8s, Yggdrasil versions every write — each apply with a change produces a new version, and the history stays queryable.

The kinds

Each accepted kind maps to a dedicated spec validator. These are the types supported today:

KindWhat it's for
integration_familyAn interface contract (shared operations and schemas) that many providers implement.
integration_typeA concrete implementation of a family (kubernetes, aws, github…), with its reactors.
integration_instanceThe deployed configuration of a type — credentials, cluster, project.
integration_quickstartAn adopter-facing manifest: "install this with one command", with inputs and steps.
productA set of integrations/workflows delivered as a single unit.
workflowA step-by-step pipeline of operations across integrations.
workflow_templateA parameterized workflow blueprint, instantiated on demand.
surfaceAn internal console/panel that renders slices of the platform.
rbacA subject-action-resource access policy.
policyA runtime policy with conditions (rate limit, data residency…).
resourceA tracked entity, originated by the core or discovered in an integration (an S3 bucket, a channel).
repository_bindingA binding between a source repository and an integration or product.
guardian_policy / guardian_approval / guardian_memoryThe approval flow and its history.
remediation_bundle / remediation_contractPieces of the incident-response flow.
control_planeDeclares the shape of the production deploy (image, replicas, Postgres, ingress, transports).
tenantA tenancy boundary for multi-tenant deploys.
ephemeral_environmentAn ephemeral-environment definition (preview / PR environments).

A kind outside this list is rejected with unsupported manifest kind — the core never persists anything it can't validate.

Versioning

An apply never overwrites anything: it appends a version. When it receives a manifest, the core:

  1. Normalizes and validates the envelope. It requires apiVersion, kind, metadata.name and a non-empty spec; it trims/lowercases and applies the kind's validator to the spec. A failure here returns 422 — nothing is written.
  2. Computes the new version number as MAX(version) + 1 within the triple (kind, namespace, name). The first time a resource is applied it's version 1.
  3. Promotes the new version to active and deactivates the previous one (active = FALSE) in the same transaction. Applying with metadata.active: false writes a "tombstone" without leaving any active version.
  4. Persists a deterministic SHA-256 checksum of the normalized document, so that re-applying identical content is detectable (the diff reports "no changes").

Because every old version stays in the table with its spec intact, the history is complete: you can fetch any version by (kind, namespace, name, version) and never lose a resource's prior shape.

A manifest in practice

A minimal integration_quickstart — the manifest that makes an integration installable with one command. Note the envelope (apiVersion + kind + metadata + spec) and how the spec carries the fields specific to the kind:

slack-quickstart.yaml
apiVersion: yggdrasil.io/v1alpha1
kind: integration_quickstart
metadata:
  name: slack
  namespace: global
  description: "Connect a Slack workspace in one command"
  labels:
    team: platform
spec:
  display_name: Slack
  providers:
    # each provider becomes an "install this" in the console
    - id: slack-bot
      display_name: Slack Bot
      requires:
        - kind: integration_type
          name: slack
      inputs:
        - id: bot_token
          label: Bot token
          type: string
          required: true
          sensitive: true
      steps:
        - id: create-instance
          uses:
            kind: integration_instance
          with:
            token: "{{ .inputs.bot_token }}"

The lifecycle

You drive everything through the CLI, which is thin: it just shapes the HTTP call to the core, which is the authority. The day-to-day flow:

Each subcommand maps to an operation in the core. Note that rollback isn't a dedicated endpoint: since every version keeps its spec, rolling back is simply re-applying the target version's spec as a new version — the history never moves backward.

lifecycle
$ yggdrasil apply -f slack-quickstart.yaml --dry-run
~ integration_quickstart global/slack (dry-run, not applied)

$ yggdrasil apply -f slack-quickstart.yaml
created integration_quickstart global/slack (version 1)

$ yggdrasil get integration_quickstart -n global
KIND                     NAMESPACE  NAME   VERSION  ACTIVE
integration_quickstart   global     slack  1        true

$ yggdrasil describe integration_quickstart slack -n global   # prints the manifest as YAML

$ yggdrasil rollback integration_quickstart slack --to 1 --yes
 rolled back integration_quickstart global/slack to the contents of v1 (new version 3)

$ yggdrasil delete integration_quickstart slack --soft   # keeps the history, active=false

Real flags worth knowing:

apply -f <file> --dry-run
Shows the diff against the active version without writing. -f - reads from stdin; multiple documents separated by --- in a single file.
diff -f <file>
Compares the file with the stored state, without applying.
get [<kind>] -n <ns> -o table|yaml|json --active-only
Lists or fetches manifests. --active-only filters to active ones only.
describe <kind> <name> -n <ns>
Prints a manifest as YAML.
rollback <kind> <name> --to <version> -n <ns> --yes
Re-applies the indicated version's spec as a new version. --yes skips the confirmation.
delete <kind> <name> [--soft] -n <ns> --yes
--soft sets active=false on all versions, preserving the history; without it the delete is hard (removes every version of the logical identity), mirroring the core's default.
Manifests are the what; execution is the how. See Workflows & runs for how a workflow manifest turns into execution, and Integrations for the four-layer model (family → type → instance → provider).