New plnt v0.1 — the orchestration runtime for agentic workflows
00 / 10 — architecture

The CRD is the contract. The saga is the engine. The backend is a choice.

plnt is nine pieces: a CRD, an operator, a Temporal workflow, a workflow-spec pull path, a Helm chart template, a backend-registration resource, a router, a smoke harness, and a rollback path. Each piece is small enough to explain on one screen.

01 / 10 — END-TO-END

From a Google Maps owner clicking a button to a reply drafted by a workflow running on your cluster. The whole path in one picture.

maps-micro-saas → microagents → plnt → cluster
  [1] Google Maps owner
      └─ opens the SaaS dashboard, clicks "draft reply" on a new review

  [2] maps-micro-saas SaaS  (the consumer product)
      └─ POST /workflows/review-responder/invoke
           {"review": "Great service but slow parking", "brand_voice": "..."}

  [3] plnt playground API  (single OpenAI-shape entry)
      └─ routes on workflow id → the currently-promoted runner pod

  [4] workflow runner pod  (installed by plnt from a microagents recipe)
      └─ executes the 3-step DAG the recipe defines:
           classify tone  →  draft reply  →  refine to brand voice
      └─ each step calls the hosted-proxy backend for the LLM

  [5] response streams back
      └─ SaaS renders the draft in the owner's dashboard, they click Send

  Behind the scenes (day zero, one time):
      microagents recipe  ─push─▶  s3://microagents/review-responder/1.2.0
      cluster admin       ─kubectl apply─▶  WorkflowRun(review-responder)
      plnt operator       ─runs saga─▶  pull → helm install → canary → promote

The runtime work — pull, canary, smoke, promote — happens once when the workflow is installed. After that, every review reply is one HTTP call. The end-user SaaS never talks to Kubernetes or S3 directly.

02 / 10 — STACK

Four layers. plnt is the third. Everything above it consumes; everything below it is Kubernetes.

PRODUCT

maps-micro-saas (or any consumer). A SaaS surface that needs narrow, reliable AI features. Calls the workflow endpoint plnt exposes — same shape for every workflow.

REGISTRY

microagents. S3-backed store of workflow specs (steps, tool bindings, GPU requirements). Versioned, hash-verifiable, pullable. Publishing is a git push + a sync job.

RUNTIME

plnt. Watches a WorkflowRun CRD → runs a Temporal saga → Helm-installs a runner pod on the chosen backend → canary → promote or rollback.

BACKEND

Any Kubernetes + GPU node pool. plnt speaks to the K8s API; backends are declared once in a PlntBackend resource and referenced by name from every WorkflowRun.

03 / 10 — DIAGRAM

One K8s cluster. One operator. One workflow engine. N workflows.

plnt · single-cluster topology
01
WorkflowRun CRD
kubectl apply · plnt.work/v1 · one file is the deploy trigger
watched ↓
02
plnt operator (kopf)
Python controller · maps create / update / delete to Temporal
start_workflow ↓
03
Temporal · OrchestrateWorkflow
pull → resolve → helm → smoke → promote (or rollback)
helm install ↓
04
Workflow runner pod
Mounts tools from the spec · exposes /invoke · returns SSE
routed via ↓
05
Envoy router
VirtualService weights · canary → stable · consumer sees one endpoint

Consumers hit /invoke through the Envoy router. Everything above the runner pod is the deploy path — it runs once per WorkflowRun change, not per request.

04 / 10 — CRD

The WorkflowRun resource is the entire deploy contract. Everything the operator, the saga, and the Helm chart need is on the spec.

examples/review-responder.yaml
apiVersion: plnt.work/v1
kind: WorkflowRun
metadata:
  name: review-responder
spec:
  workflow:
    ref: review-responder@1.2.0
    registry: s3://microagents           # or oci://ghcr.io/...
    integrityHash: sha256:9a1b...          # optional pin
  backend:
    cluster: gpu-cluster-01                # named plnt backend
    gpuClass: nvidia.com/h100
    gpuCount: 2
    nodeSelector:
      pool: agent-workflows
  replicas:
    min: 1
    max: 4
  autoscaling:
    targetInvocationsPerSecond: 25
  canary:
    trafficPercent: 5
    smokeTest:
      invocations: 10
      p95BudgetMs: 2500
      errorBudgetPercent: 1
05 / 10 — WORKFLOW SPEC

The thing plnt pulls from the registry. A workflow is a directed graph of steps + tool bindings + resource requirements.

microagents/review-responder/workflow.yaml
# microagents/review-responder/workflow.yaml
apiVersion: microagents.dev/v1
kind: Workflow
metadata:
  name: review-responder
  version: 1.2.0
spec:
  description: Draft an on-brand reply to a Google Maps review.
  runtime:
    image: ghcr.io/microagents/runner:0.4.0
    entrypoint: python -m review_responder
  steps:
    - id: classify_intent      # sentiment + topic
      tool: llm.classify
    - id: retrieve_brand_voice # RAG from tenant KB
      tool: rag.query
      deps: [classify_intent]
    - id: draft_reply
      tool: llm.generate
      deps: [retrieve_brand_voice]
    - id: safety_check
      tool: policy.moderate
      deps: [draft_reply]
  requirements:
    gpuClass: nvidia.com/h100
    gpuCount: 2
    memoryGiB: 40
06 / 10 — OPERATOR

A Python kopf controller watches the CRD. Create / update / delete map directly to Temporal workflow starts, updates, and cancellations.

plnt/operators/workflowrun_controller.py
# plnt/operators/workflowrun_controller.py
import kopf
from temporalio.client import Client
from plnt.workflows.orchestrate import OrchestrateWorkflow

@kopf.on.create('plnt.work', 'v1', 'workflowruns')
async def on_create(spec, name, namespace, **_):
    client = await Client.connect(TEMPORAL_ADDR)
    await client.start_workflow(
        OrchestrateWorkflow.run,
        args=[spec],
        id=f'orchestrate-{namespace}-{name}',
        task_queue='plnt-orchestrate',
    )

@kopf.on.update('plnt.work', 'v1', 'workflowruns')
async def on_update(spec, name, namespace, **_):
    # Any spec change triggers a fresh canary.
    ...

@kopf.on.delete('plnt.work', 'v1', 'workflowruns')
async def on_delete(name, namespace, **_):
    # helm uninstall + cancel any in-flight orchestration.
    ...
07 / 10 — SAGA

The orchestration saga is a Temporal workflow. Compensation on failure via helm rollback. Retries per activity, non-retryable error types short-circuit obvious dead-ends.

plnt/workflows/orchestrate.py
# plnt/workflows/orchestrate.py
from datetime import timedelta
from temporalio import workflow
from temporalio.common import RetryPolicy

@workflow.defn
class OrchestrateWorkflow:
    @workflow.run
    async def run(self, spec: dict) -> dict:
        retry = RetryPolicy(
            initial_interval=timedelta(seconds=2),
            maximum_attempts=3,
            backoff_coefficient=2.0,
            non_retryable_error_types=['SpecInvalid', 'BackendUnavailable'],
        )
        try:
            await workflow.execute_activity(
                pull_workflow_spec, spec, start_to_close_timeout=timedelta(minutes=5), retry_policy=retry)
            await workflow.execute_activity(
                resolve_backend, spec, start_to_close_timeout=timedelta(seconds=30), retry_policy=retry)
            release = await workflow.execute_activity(
                helm_install_canary, spec, start_to_close_timeout=timedelta(minutes=10), retry_policy=retry)
            smoke = await workflow.execute_activity(
                run_smoke_test, release, start_to_close_timeout=timedelta(minutes=5), retry_policy=retry)
            if not smoke['passed']:
                await workflow.execute_activity(helm_rollback, release)
                return {'status': 'rolled_back', 'reason': smoke['reason']}
            await workflow.execute_activity(
                promote_to_stable, release, start_to_close_timeout=timedelta(minutes=5))
            return {'status': 'ready', 'endpoint': release['endpoint']}
        except Exception:
            await workflow.execute_activity(helm_rollback, spec)  # compensation
            raise
08 / 10 — LIVE RUN

One orchestration. Captured from the Temporal event history for orchestrate-default-review-responder.

temporal · workflow history · r-9c4f218e0a
04:17:33 watch WorkflowRun/review-responder event=create
04:17:33 workflow start · orchestrate-default-review-responder
04:17:34 pull spec ref=review-responder@1.2.0 · source=s3://microagents · sha256 verified
04:17:35 resolve backend=gpu-cluster-01 · gpus=2 available · node pool=agent-workflows
04:17:41 helm install release=review-responder-canary · replicas=1 · vs.weight=5%
04:19:14 smoke n=10 · p50=1.1s p95=1.8s · errors=0 · pass
04:19:15 promote canary → stable · vs.weight=100% · replicas=1→3
04:19:15 ready endpoint=review-responder.plnt.svc/invoke
09 / 10 — METRICS

The numbers that prove the runtime works: p50/p95/p99 per-invocation latency, error rate, GPU utilization, queue depth. Scraped from each workflow's /metrics endpoint into Prometheus.

plnt bench --workflow review-responder --qps 10 --duration 60s
latency     p50 =   1.10 s   p95 =   1.82 s   p99 =   2.41 s
error rate                  =   0.00 %
throughput                  =   9.7  invocations/s
gpu utilization             =   68 %
step-cache hit rate         =   34 %
10 / 10 — GAPS

Where the current build is honest about what it isn't. Named upfront, not hidden.

Registry publishing UX

microagents ships a pull path; the push path is a manual S3 sync. A proper microagents publish CLI + signature verification is planned Q1 2026.

Multi-cluster

Single-cluster demo today. Multi-cluster is a design I understand (fan-out activities keyed by cluster context; per-cluster canary) but not yet code I've run at scale.

GPU scheduling policy

plnt respects nvidia.com/gpu limits and node selectors; it does not yet do capacity-aware placement across pools. The scheduler-plugin work is Phase 5.

Observability

Temporal history + Kubernetes events cover the deploy lane. Per-invocation tracing (OpenTelemetry span per workflow step) is stubbed but not wired to a collector yet.