Get started

Pick where it runs. Then publish a product and run it.

Three ways to install, the same charts underneath each. Your laptop costs nothing and takes a few minutes; a cloud install shows you its bill before it changes anything. Vennir is 0.x: try it, but read the gaps before you trust it with production.

What you need

Kubernetes 1.30 or later, Helm 4, and a CNI that enforces NetworkPolicy.

The charts refuse older Kubernetes and older Helm. Without NetworkPolicy enforcement, the platform's databases and kernel-api aren't fenced off from steps. vennir runs on macOS and Linux, amd64 and arm64.

vennir tools --install downloads what's missing into ~/.vennir/bin, each at a pinned version checked against its project's checksum. Docker and the cloud CLIs are yours to install.

For Needs
Every install kubectl (pinned 1.37.1), helm 4 (pinned 4.3.0)
Your laptop Docker, running, about 4 GB of memory free; kind (pinned 0.33.0)
GKE gcloud, gke-gcloud-auth-plugin, OpenTofu tofu (pinned 1.13.1)
EKS aws CLI v2, OpenTofu tofu
Your cluster A kubectl context that reaches it; ValidatingAdmissionPolicy available; kubectl within one minor version
The catalog git, gh signed in with the repo and workflow scopes
01 · On your laptop

A real install in kind, in a few minutes.

Both ways build a kind cluster and a local image registry at localhost:5001, and install the kernel and the console into vennir-system, with the same admission policies a cloud install gets.

From a clone of the repository make quickstart
# Needs Docker running, kind, kubectl, helm 4 and curl
$ git clone https://github.com/rburns629/vennir
$ cd vennir
$ make quickstart    # safe to run again

# Console at http://localhost:18080
$ make logs          # follow every component
$ make down          # stop, keeping the data
$ make up            # start again

Builds the platform from your checkout, creates the cluster vennir-local and the team team-a, and port-forwards the console.

With the installer vennir, target kind
# vennir from the GitHub release for your OS
$ vennir tools --install
$ vennir init dev --target kind
$ vennir apply dev    # $0: nothing billed

# Reach the console on http://localhost:18080
$ vennir console dev
$ vennir sleep dev    # and vennir wake dev

Asks the cluster's name, the registry port, the size, the first admin's email and what else to keep, then installs a release, or your checkout with --source.

Signing in locally

After make quickstart, sign in as admin@example.com with the password vennir-local. It's set only in the kind values, for a cluster nobody else can reach: never use it anywhere else. vennir generates the first admin's password instead, never prints it, and saves it to deploy/<env>/admin-password, readable only by you; you change it at the first sign-in.

Runs → Submit a DAG your first DAG
{
  "name": "my-first-run",
  "tasks": [
    {
      "id": "create-project",
      "image": "localhost:5001/demo-project-product:local",
      "action": "create",
      "team": "team-a",
      "serviceAccount": "default",
      "inputs": { "projectName": "hello" }
    },
    {
      "id": "deploy-app",
      "image": "localhost:5001/demo-application-product:local",
      "action": "create",
      "team": "team-a",
      "serviceAccount": "default",
      "dependsOn": ["create-project"],
      "inputs": {
        "projectId": { "$fromTask": "create-project", "$output": "projectId" }
      }
    }
  ]
}

Try it with no catalog at all

After make quickstart, paste this into Runs → Submit a DAG. Both images are the fake products in examples/. create-project outputs {"projectId": "hello-123"}, and deploy-app runs next with it filled in.

Then publish real products to the local registry, with no Git hosting or CI. Each is validated, built, tested and scanned the way catalog CI does it, then registered with the console.

Local mode
# the sample team: one product in five languages
$ make catalog-publish
# or a catalog folder of your own
$ make catalog-publish CATALOG=../my-catalog
02 · On GKE or EKS

Answer, read the bill, approve.

vennir makes the cluster with OpenTofu, under your own cloud sign-in, and installs the charts. Nothing changes until you approve, and running it again finds less to do, never duplicates.

Google Cloud: a project with billing guide
$ gcloud auth login
$ gcloud auth application-default login
$ gcloud components install \
    gke-gcloud-auth-plugin
AWS: an account, not a Builder ID guide
# an IAM user, no keys on disk
$ aws login --profile vennir
# or IAM Identity Center
$ aws configure sso --profile vennir
GitHub: for the catalog guide
$ gh auth login \
    --scopes repo,workflow

vennir init prod asks, in order

Each choice says what it costs or gives up. Every answer is kept in deploy/prod/vennir.yaml: names only, never a secret. vennir config set changes one later.

  1. 01Where. gcp or aws; the project or profile, and a region your policies allow
  2. 02Cluster mode. auto (GKE Autopilot, EKS Auto Mode) or standard node pools
  3. 03Size. minimal, resilient, scaled or auto, each with its copies and step caps
  4. 04Sleep when idle. Scale to zero after a quiet spell, data kept; for dev and test installs
  5. 05Database. Postgres in the cluster, backed up to a bucket, or Cloud SQL or Amazon RDS with no passwords of Vennir's
  6. 06First admin. Their email; the password comes once, after the first apply
  7. 07The console. Private, reached with vennir console, or public over HTTPS at a hostname
  8. 08The catalog. A GitHub repository, its first team and starter languages, and image signing: none, a KMS key, or keyless
  9. 09What else it keeps. Log search, the audit log's write-once copy, the API gateway, and Prometheus for alerts
vennir apply prod · the approval screen
$ vennir apply prod

Vennir [VERSION] → gcp / my-project / us-central1,
  new cluster vennir (auto: GKE Autopilot)

Tools        kubectl, helm, tofu, gcloud: all present
Size         minimal: platform 0.55 vCPU, 1.75 GiB awake
Scale down   yes: sleeps after 2h idle
Steps        at most 10 at once (5 per team), Spot
Images       scanned; signed with a Cloud KMS key
Backups      daily to a new bucket, kept 30 days
Catalog      github.com/my-org/vennir-catalog (private)

Will create  cluster, network, 2 registries, KMS key,
             backup bucket, identities, catalog federation
Will install execution-kernel, execution-console
             into vennir-system

Estimated monthly cost (list prices, fetched now)
  Always        [FROM YOUR CLOUD'S PRICES]
  While awake   [FROM YOUR CLOUD'S PRICES]
  Steps         [PER STEP-HOUR]
  Not included: discounts, taxes, egress,
  your products' own cloud usage

Apply? [y/N] y

What apply creates

Prices come live from your cloud's own price lists, never from numbers built into the CLI; if they can't be fetched, the screen says so rather than guess. A first cloud install takes about ten to twenty minutes.

  • gcp

    A VPC; GKE Autopilot or Standard with Workload Identity; Artifact Registry for platform and task images; service accounts for the console, scanner, backups and External Secrets; a Cloud KMS key; Workload Identity Federation for the catalog's main; a backup bucket or Cloud SQL.

  • aws

    A VPC; EKS Auto Mode or managed node groups with Pod Identity and NetworkPolicy enforcement on; ECR; IAM roles; a KMS key; a GitHub OIDC provider and a role limited to the catalog; an S3 backup bucket or RDS; a Route 53 zone for a public console.

  • both

    The platform namespace, policy-controller when signing is on, External Secrets Operator, then the kernel and console charts. Public console: a certificate and, for a hostname of yours, the exact DNS record to add.

Day to day vennir help settings
$ vennir status prod      # awake or asleep, address, certificate
$ vennir console prod     # http://localhost:18080
$ vennir sleep prod       # scale to zero, data kept
$ vennir wake prod
$ vennir backup prod
$ vennir config set -e prod vennir <x.y.z>
$ vennir apply prod       # upgrade; back up first
$ vennir destroy prod     # asks about each kind of data

Sleep and wake

The sleeper never sleeps while a run is unfinished, and wakes itself for a schedule that's due. While asleep the console and API don't answer, so catalog CI and automation fail until vennir wake. Keep production awake.

What destroy keeps

Unless you choose otherwise: the database's disk, the backups and logs buckets, and the task registry. The audit copy's bucket is always kept: it's the record, and its retention refuses deletion until it lapses.

03 · On a cluster you have

The charts are complete on their own.

Each release publishes both charts and their signed images to ghcr.io/rburns629/vennir. A chart install makes both databases, generates their passwords and the first admin. vennir init --target existing uses the same charts, and can set up HTTPS through your Ingress with cert-manager.

  1. 01A platform namespace, such as vennir-system. Never a team's; keep who may create Pods there to administrators.
  2. 02Optional components first: Sigstore's policy-controller for signatures (excluding the platform namespace), External Secrets Operator for vaults.
  3. 03Values, copied from helm/values/{kind,gke,eks}. At least the task image source, the console's kernelApiUrl and the first admin's email.
  4. 04Install, kernel first, without --wait the first time: each chart migrates in a post-install hook. Then port-forward, or put HTTPS in front before anyone signs in over a network.
Installing with Helm, in full
docs/operations.md helm 4
CHARTS=oci://ghcr.io/rburns629/vennir/charts
V=<release>; SIZE=minimal

helm pull $CHARTS/execution-kernel --version $V --untar
helm pull $CHARTS/execution-console --version $V --untar

helm install kernel ./execution-kernel -n vennir-system \
  -f execution-kernel/sizes/$SIZE.yaml -f <values>/kernel.yaml
helm install console ./execution-console -n vennir-system \
  -f execution-console/sizes/$SIZE.yaml -f <values>/console.yaml

kubectl -n vennir-system rollout status deployment \
  -l 'app.kubernetes.io/instance in (kernel,console)'

# The first admin's password: never printed, so set one
kubectl -n vennir-system exec deploy/console-execution-console -- \
  node dist/db/resetAdmin.js <email>

# kernel-api must stay ClusterIP
kubectl -n vennir-system port-forward \
  svc/console-execution-console 18080:8080
Your first catalog

A repository of products, published as one signed release.

Adding a product is a reviewed pull request. CI holds no console or cluster credential: it pushes to the registry, and each install's console pulls the release, verifies it and applies it.

  1. 01 · Pull request ./vennir catalog check validates, builds, tests and scans. Nothing is published.
  2. 02 · Merge to main Changed products pushed to <registry>/<team>/<product> and signed.
  3. 03 · Release ./vennir catalog release pushes every team and product as one signed OCI artifact, catalog-release.
  4. 04 · Each console Polls it, checks the signature, then creates teams and namespaces and registers products.
On a gcp or aws install vennir catalog create
$ vennir catalog create prod

# Creates the repository from catalog-template/,
# its first team and your starter languages,
# sets its registry and signing variables,
# waits for the first release, has the console
# apply it, and runs a starter end to end.

Starters come in Python, TypeScript, Go, PowerShell and Rust. On GitHub Free, a private repository has no Environments or branch rules; publishing is still limited to main by its cloud federation. A released vennir carries the catalog template for its own version, so make the catalog with the same version the install runs.

On kind or your own cluster, start from catalog-template/ by hand and publish with ./vennir catalog publish or make catalog-publish.

teams/team-a/products/hello/product.yaml from templates/hello
apiVersion: vennir.dev/v2
kind: Product
name: hello
team: team-a                 # CHANGE
displayName: Hello
owner: team-a                # CHANGE
runtime: python3.12
actions:
  - name: greet
    script: actions/greet.py
    input:
      type: object
      required: [name]
      properties:
        name: {type: string}
        useSecret: {type: boolean}
    output:
      type: object
      required: [message]
      properties:
        message: {type: string}
        secretFound: {type: boolean}
    secretRefs:
      - {name: hello-secret, keys: [value]}
Your first run

Run a template, or fill a cart.

People who use your products never write a DAG. Each step runs as its product's own identity and secrets, which nobody running it chooses or sees.

teams/team-a/dags/say-hello.yaml a template
apiVersion: vennir.dev/v2
kind: Template
name: say-hello
displayName: Say hello
description: Greets whoever you name.
parameters:
  type: object
  additionalProperties: false
  required: [name]
  properties:
    name: {type: string, title: Name}
steps:
  - id: say-hello
    action: hello.greet
    inputs:
      name: {$param: name}

Merged, it appears in Catalog. Choose Run, fill in the form made from its parameters, and follow the run live. Show as an API call gives a bot the same run.

  1. 01 Add to cartIn Catalog, on each action you want. Its card says whether it's ready on this install.
  2. 02 Open Cart, pick the teamThe console works out the order: which output feeds which input, and adds a step something needs.
  3. 03 Fill in what's asked onceValues shared by the whole order, and a choice where more than one thing could fill an input.
  4. 04 Place orderOne run for your team, each step checked as if you ran it alone, so a cart never does more than you could step by step.

The rest is in the guides.

Setup from an empty account, the hour-long walkthrough from a new team to two chained products, and every setting with its default.

Setting up Vennir Try it end to end The catalog's guide
Stuck? Troubleshooting says what to check when something fails, or ask the community.