Run intents
on Kubernetes

Kubernetes reconciliation is battle-tested and free, but using it has meant writing an operator.
Inrun opens it to anything that takes a request and returns a response: a template, a service in any language, an API you already run, or Go.
Callers send an intent in their own words and read back a view. You bring the decision; Inrun brings the machinery.

$ brew install intentd/tap/inrun
Intent in
through the gateway

Callers send JSON or YAML in the field names the Blueprint declares, with a token. The gateway checks it against the CRD's admission rules and builds the custom resource. No caller sees a CRD schema.

Reconcile
one contract, any reconciler

Templates, a service you already run, or Go: every reconciler gets the same request and returns the same Result. Inrun runs the informers, queues, retries, finalizers, status and every write.

View out
only what the Blueprint declares

The caller polls the gateway and reads a view: the fields serve.view declares, not the whole object. The custom resource never has to leave the cluster.

Quick Start

Reconciling in a minute

inrun init scaffolds a Blueprint, a CRD and a CR. inrun simulate checks it with no cluster; --dev creates a kind cluster to run it on.

OS
Method
inrun init · inrun simulate · inrun --dev
zsh
Reconcilers

Write only the decision

A reconciler decides what a resource should become. Watching, queueing, retrying, applying, pruning, status, events and deletion belong to the runtime. Pick the reconciler per CRD, or per serve target; the CRD's API stays the same.

The reconciler contract
blueprint.yaml A complete reconciler · No code
apiVersion: inrun.dev/v1
kind: Blueprint
metadata:
  name: hello-website
spec:
  crds:
    website:
      crdFile: ./manifests/crd.yaml
      operatorBox:
        reconcile:
          onCreate:
            deployments:
              - name:  "{{ .metadata.name }}"
                image: "{{ .spec.image }}"
        emit:
          status:
            fields:
              - path: phase
                value: Running
Gateway

Callers never touch Kubernetes

Add serve to a CRD and the gateway accepts intents for it: the fields a caller may send, the tokens that may send them, and the view they read back. The reconciler never reads the CR either: the Blueprint maps between the two sides.

A CI pipeline
A frontend form
The console
curl
POST /api/v1/apply The caller's own field names
{ "target": "website",
  "name": "hello-intent",
  "image": "nginx:1.27",
  "replicas": 2 }

// → 202, and a URL to poll
Why Inrun

What comes with it

Kubernetes as a backend

State that keeps itself true

A custom resource can be a durable state machine: Kubernetes stores it, Inrun retries it until the decision holds, and cleans it up when it's done. Nothing has to be a Deployment.

Shared as patterns

Blueprints with their proof

inrun push publishes a Blueprint to any OCI registry with its simulate and e2e results; inrun inspect shows them before anyone runs it.

The schema can change

Under live data

migrate.from moves fields to new paths and migrate.to moves resources to a new CRD, with rollback, while callers keep sending the same intents.

No CRDs of its own

Your CRDs, a Blueprint file

The Blueprint is a ConfigMap in the cluster. Remove Inrun and nothing of Inrun's is left in your API server.

Writes are fenced

Only what the Blueprint allows

Inrun does every write, only for kinds a CRD declares, with RBAC generated from the Blueprint.

Deletion waits

For your reconciler, with a bound

Every CR carries Inrun's finalizer. Your reconciler finishes its cleanup first; a timeout keeps it from hanging forever.

Tested before a cluster

simulate, envtest, e2e

inrun simulate runs the runtime's own reconcile pass in memory; inrun e2e checks the same example on kind.

Per serve target

One CRD, several reconcilers

Templates for one target, a remote service or Go for another. The caller picks the target; the API stays one CRD.

Kubernetes-aware templates

Functions

Pod readiness, job completion, quantities, cron, semver and more, as functions in every template, plus your own.

Console

See every CRD, worker and resource

The console reads each runtime's /blueprint API: CRDs, how each is reconciled, worker pools, queues, CRs and their status. It creates resources through the gateway, the same path as an intent.

Try it in Learning Inrun →
localhost:8081
platform-operator
infra-operator
database-operator
platform-operator ● Healthy
4CRDs
16Workers
247Resources
0Errors
database
● Healthy · 4 workers
Queue: 3/64 · Uptime: 48h
application
● Healthy · 4 workers
Queue: 2/64 · Uptime: 47h
cache
⚠ Pending · 0 workers
Waiting for: database
ingress
● Healthy · 4 workers
Queue: 1/64 · Uptime: 48h
Components

Three processes, one CLI

inrun runs them on your machine; the Helm chart runs them as Deployments.

runtime

Runtime

Watches your CRDs and their children, runs each reconcile pass, applies the Result, and exposes /blueprint. Leader-elected.

gateway

Gateway

Takes intents and returns views, and serves the admission and conversion webhooks over TLS. Stateless, several replicas.

console

Console

A live view of one or more runtimes, and a form that sends intents through the gateway.

Community

Any help is welcome

A bug report, a docs fix, an example. Built in the open, Apache 2.0.

Learn

Start here

→→

Learning Inrun

Your first reconciled resource with inrun init, then six example packs in order: declarative, remote, typed, intent, migration, registry.

✎→

Why I Built This

A missed interview, a wall of boilerplate, and a pattern that kept repeating, until the project turned out to be an intent runner.