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.
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.
[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.
Four layers. plnt is the third. Everything above it consumes; everything below it is Kubernetes.
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.
microagents. S3-backed store of workflow specs (steps, tool bindings, GPU requirements). Versioned, hash-verifiable, pullable. Publishing is a git push + a sync job.
plnt. Watches a WorkflowRun CRD → runs a Temporal saga → Helm-installs a runner pod on the chosen backend → canary → promote or rollback.
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.
One K8s cluster. One operator. One workflow engine. N workflows.
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.
The WorkflowRun resource is the entire deploy contract. Everything the operator, the saga, and the Helm chart need is on the spec.
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 The thing plnt pulls from the registry. A workflow is a directed graph of steps + tool bindings + resource requirements.
# 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 A Python kopf controller watches the CRD. Create / update / delete map directly to Temporal workflow starts, updates, and cancellations.
# 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.
... 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
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 One orchestration. Captured from the Temporal event history for orchestrate-default-review-responder.
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.
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 %
Where the current build is honest about what it isn't. Named upfront, not hidden.
microagents ships a pull path; the push path is a manual S3 sync. A proper microagents publish CLI + signature verification is planned Q1 2026.
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.
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.
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.