Skip to content

Add "How to Run AI Agents on Kubernetes with Pulumi" blog post - #20550

Merged
CamSoper merged 4 commits into
masterfrom
blog/ai-agents-on-kubernetes
Jul 30, 2026
Merged

Add "How to Run AI Agents on Kubernetes with Pulumi" blog post#20550
CamSoper merged 4 commits into
masterfrom
blog/ai-agents-on-kubernetes

Conversation

@joeduffy

Copy link
Copy Markdown
Member

What

Adds a new evergreen blog post, "How to Run AI Agents on Kubernetes with Pulumi" (content/blog/ai-agents-on-kubernetes/index.md, authors: joe-duffy), and fixes two pre-existing bugs in the HowTo schema template found while verifying this post's structured data.

Why this post, why now

Kubernetes is where the "agentic AI" conversation is increasingly landing: CNCF's January 2026 annual survey found 66% of organizations are betting on Kubernetes to run generative AI workloads. A real ecosystem has grown up around that (kagent, KServe, Kueue, KubeRay, vLLM/llm-d, Dynamic Resource Allocation, the Gateway API Inference Extension), but most of it assumes the cluster and its governance are already handled. This post covers the gap: what's different about provisioning for an agent workload versus a normal service, a fair and generous survey of that ecosystem (Pulumi's job is to provision and govern underneath these tools, not compete with them), a TypeScript + Python walkthrough for provisioning agent infrastructure with Pulumi, why a general-purpose language earns its keep as configuration branching grows (while conceding Helm/Kustomize are fine for simple, static manifests), a governance section (Pulumi Policies, ESC, RBAC, and a precise Insights-vs-Neo distinction on cost claims), where Pulumi Neo fits, and a 6-question FAQ.

Reviewed by Joe Duffy (via an internal review pass) for voice and technical accuracy; two sentences were revised to speak in first person per that feedback, and the Insights-vs-Neo distinction was confirmed as correct and worth keeping explicit.

Keyword / AEO rationale

  • Primary target: "AI agents on Kubernetes" — Profound tracking shows zero prompts today combining Kubernetes + AI agents, i.e. genuine whitespace, while pulumi.com is already the Quickstart for LM release #4 most-cited domain (5.2% citation share) on the broader AI-infrastructure topic. First-mover citation opportunity.
  • Secondary: "ai in devops"/"ai devops" (~6,000 monthly impressions, no purpose-built Pulumi page today), "pulumi kubernetes operator" (913 impressions, avg. position 4.5), "kubernetes best practices" (115K impressions, position 3.3 — used here as an internal-link anchor for authority transfer), "kubernetes iac" (144 impressions, position 3.7).
  • Structured for extraction per our GEO practice: answer-first paragraphs, H2/H3s phrased as real questions, comparison tables over prose, cited stats with sources, numbered steps for the walkthrough.

Schema: FAQPage + HowTo, and the honest caveat

The post sets faq_schema: true and a new howto_schema: true flag, both additive to the post's normal BlogPosting entity — i.e. the rendered @graph includes BlogPosting, FAQPage, and HowTo all at once, not one replacing another.

Important context on rich results: Google deprecated FAQPage rich results in Search on 2026-05-07 (API support removed 2026-08), following HowTo's 2023 deprecation. Neither schema type produces a rich result today. I'm including this markup anyway because it's accurate, machine-readable structure that costs nothing and may still help LLM crawlers parse the page's Q&A/step structure, but I want to be explicit in this PR that it is not a proven citation lever — see the discussion in 2026_geo_schema_citation_study_findings — so nobody should read "we added FAQ/HowTo schema" as a growth bet in itself.

Template changes (and why they were necessary)

While building a disposable local Hugo harness to verify this post's JSON-LD before pushing (copying layouts/partials/schema/* into a throwaway site and rendering), I found the existing howto-entity.html was silently broken for every page that already uses schema_type: howto, not just this new post:

  1. Every HowToStep.text field rendered as just a whitespace string ("\t\n\r"), never the actual step content. Root cause: {{ $stepText | ... | trim " \t\n\r" }} — Hugo's trim piped this way receives the piped value as its cutset argument and the accumulated step text is dropped. Fixed at all three step-emission sites to call trim directly with the step text as the first argument.
  2. A step already saved on the blank line after the last numbered-list item could be appended a second time once the next heading was reached, because $stepText/$inNumberedList were only reset on a header line, not on the blank line that (correctly) already triggers the first save. Fixed by unconditionally clearing both after the end-of-step block runs.

I verified both fixes render correctly (clean single-sentence step text, no duplicate steps) against this post and a couple of minimal synthetic fixtures before pushing. The harness itself was not committed.

Additionally, graph-builder.html gets a new additive howto_schema: true gate for blog posts (mirrors the existing faq_schema opt-in pattern), guarded to never fire alongside schema_type: howto so the two mechanisms can't both emit a HowTo entity for the same page. This is template-level leverage: any future how-to-shaped blog post can now carry BlogPosting + HowTo + FAQPage together, rather than needing to give up its BlogPosting entity (author, date, publisher) to get HowTo, or a per-page hack.

Fact-check table

Claim Source
66% of orgs betting on Kubernetes for generative AI workloads CNCF Annual Survey Report, Jan 2026: https://www.cncf.io/wp-content/uploads/2026/01/CNCF_Annual_Survey_Report_final.pdf
kagent CNCF Sandbox, accepted May 22, 2025 https://www.cncf.io/projects/kagent/
kagent CRD kinds (Agent, ModelConfig, ModelProviderConfig, RemoteMCPServer, SandboxAgent), v0.9.9 current release https://github.com/kagent-dev/kagent (go/api/v1alpha2/), https://kagent.dev/docs/kagent/introduction/installation
KServe CNCF Incubating, accepted Sept 29, 2025 https://www.cncf.io/blog/2025/11/11/kserve-becomes-a-cncf-incubating-project/
Dynamic Resource Allocation GA in Kubernetes v1.34 https://kubernetes.io/blog/
kubernetes.helm.v4.Chart, kubernetes.Provider, kubernetes.apiextensions.CustomResource, kubernetes.yaml.v2.ConfigFile/ConfigGroup https://www.pulumi.com/registry/packages/kubernetes/api-docs/
Pulumi Neo documented capabilities (Q&A, propose-as-PR, preview, PR review, recurring maintenance) https://www.pulumi.com/docs/ai/
FAQPage rich results deprecated 2026-05-07; HowTo deprecated 2023 Google Search Central changelog

I did not independently verify the exact kagent.dev/v1alpha2 API group string (only the CRD kinds and version path, via the live GitHub source) — the post includes an explicit caveat telling readers to check kagent's own CRD manifests before shipping the sample to production.


🧠 This PR was created by workprentice on behalf of @joeduffy.

New evergreen blog post (authors: joe-duffy) covering how to provision and
govern Kubernetes infrastructure for agentic AI workloads with Pulumi:
what changes about K8s infra when the workload is an agent, a fair survey
of the agentic-Kubernetes ecosystem (kagent, KServe, Kueue, KubeRay,
vLLM/llm-d, DRA, Gateway API Inference Extension, NVIDIA GPU Operator),
a TypeScript + Python walkthrough for provisioning agent infra, why
general-purpose languages help as configuration branching grows, a
governance section (Pulumi Policies, ESC, RBAC, and a precise Insights vs.
Neo distinction), where Pulumi Neo fits, and a 6-question FAQ.

Also fixes two pre-existing bugs found while building a local schema
render harness to verify this post's structured data:

- layouts/partials/schema/collectors/howto-entity.html: `trim` was being
  piped as `$stepText | ... | trim " \t\n\r"`, which passes the trim
  cutset as the piped value and the accumulated step text as an unused
  argument, so every HowTo step's `text` field silently rendered as just
  the whitespace cutset instead of the actual step content across all
  three step-emission call sites. Fixed to call `trim` directly with the
  step text as first argument. Also fixed a related bug in the same file
  where hitting an empty line right after the last numbered-list item
  could get that final step appended a second time when a later heading
  was reached, because $stepText/$inNumberedList were only reset on a
  header line, not on the blank line that (correctly) triggers the first
  save.
- layouts/partials/schema/graph-builder.html: added an additive
  `howto_schema: true` frontmatter gate for blog posts, so a how-to-style
  blog post can carry a HowTo entity alongside its normal BlogPosting
  entity (author, date, publisher) rather than only being able to fully
  replace BlogPosting via the existing `schema_type: howto` gate. Mirrors
  the existing `faq_schema` opt-in pattern; guarded so it never fires
  alongside `schema_type: howto` to avoid emitting HowTo twice.

Verified both fixes and the new post's JSON-LD (BlogPosting + FAQPage +
HowTo all present, 12 FAQ entries, 6 clean HowTo steps) by copying the
schema partials into a disposable local Hugo site and inspecting the
rendered output; harness was not committed.

Per Google's 2026-05-07 deprecation of FAQPage rich results (following
HowTo's 2023 deprecation), this markup is now hygiene-level machine-
readable structure rather than a rich-result or proven AI-citation lever;
noted plainly in the PR description rather than oversold.
@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Social Media Review

content/blog/ai-agents-on-kubernetes/index.md

X — PASS

LinkedIn — PASS

Bluesky — PASS


Suggestions (advisory)

These are stylistic notes — they don't block the post.

X

  • "Gets expensive fast" doesn't name what actually gets expensive — no cost, security, or blast-radius detail backs the claim, unlike the CNCF stat that opens the post
  • Pointer "How to provision and govern it with Pulumi:" ends with a colon, reading like a list header rather than a closing line

LinkedIn

  • Final paragraph names the specific topics the article covers (policy-as-code, secrets management, Pulumi Neo) — this recaps the article's contents instead of withholding them

Bluesky

  • The construction "GPUs, long-lived sessions, and a much bigger credential blast radius" echoes the staccato noun-phrase pattern the guide flags as LLM-characteristic

Updated for commit 1d969c587d66061da1d44782ea1a81ea06eec19d (short: $(echo "1d969c587d66061da1d44782ea1a81ea06eec19d" | cut -c1-7)) at $(date -u '+%Y-%m-%d %H:%M UTC').

@pulumi-bot

pulumi-bot commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

@pulumi-bot

pulumi-bot commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Lighthouse Performance Report

Commit: 1d969c5 | Metric definitions

Page Device Score FCP LCP TBT CLS SI
Homepage Mobile 🔴 29 6.2s 12.8s 1954ms 0.001 9.2s
Homepage Desktop 🟡 88 0.8s 1.9s 144ms 0.014 1.2s
Install Pulumi Mobile 🟡 56 5.9s 15.0s 109ms 0.053 8.0s
Install Pulumi Desktop 🟡 75 1.2s 2.9s 0ms 0.005 2.7s
AWS Get Started Mobile 🟡 57 5.8s 9.4s 34ms 0.071 7.8s
AWS Get Started Desktop 🟡 75 1.2s 2.9s 0ms 0.033 2.7s

@joeduffy

Copy link
Copy Markdown
Member Author

@claude #new-review — this PR was opened while conflicted against a stale base (10 days old), so the initial triage/review never ran (zero pull_request workflow runs fired at all until this fix). Rebased onto current master, resolved the single conflict in graph-builder.html (kept both this PR's howto_schema additive block and master's technology-entities wiring from PR #20535 — verified via a local Hugo build that both still emit correctly in the rendered JSON-LD), fixed a social-review char-limit failure on the X/Twitter copy (was 19 chars over once the auto-appended URL is counted), and pushed. Build, tests, and social-review are all green now. Requesting a first full review.

@github-actions github-actions Bot added the review:in-progress Claude review is currently running label Jul 29, 2026
@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Pre-merge Review — Last updated 2026-07-29T01:25:00Z

Tip

Summary: This PR adds a new long-form blog post — How to Run AI Agents on Kubernetes with Pulumi — plus two Hugo schema-template changes that let a blog post emit HowTo structured data alongside its normal BlogPosting entity. Both findings from the initial review are now fixed in commit 36a9c960e3b: the Kubernetes v1.34 release-date footnote now reads "August 27, 2025" (matching the source), and the "kagent is the most Kubernetes-native option" superlative is softened to "one of the more Kubernetes-native options." The same commit also splits the Bluesky social copy into two paragraphs, addressing a separate social-review-bot flag unrelated to this review. This pass re-verified both previously-contradicted claims against the corrected text and swept the whole file for missed duplicates of "September 2025" and "most Kubernetes-native" — none found.

Review confidence:

Dimension Level Notes
mechanics HIGH
facts MEDIUM both confirmed errors from the initial review fixed in 36a9c960e3b; 4 unverifiable claims remain (non-blocking)
coherence MEDIUM code walkthrough still stops at step 4 of 6 (steps 5–6 in prose only) — author confirmed this is intentional
editorial balance MEDIUM provisioning section is 11.7× the median — expected for a how-to walkthrough
code correctness MEDIUM TS/Python blocks clean; the two Hugo schema templates were read-reviewed but not build-validated in preflight (the full build job covers them)
Investigation log
  • Cross-sibling reads: not run (not in a templated section)
  • External claim verification: 39 of 71 claims verified (6 unverifiable, 3 contradicted) · 4 specialists (numerical, cross-reference, capability, framing); 0 cross-specialist corroborations · routed: 0 inline, 34 Pass 1, 13 Pass 2 (verified 8, contradicted 2, unverifiable 3), 24 Pass 3 (verified 8, contradicted 1, unverifiable 15).
  • Cited-claim spot-checks: 13 of 13 cited claims fetched and compared
  • Frontmatter sweep: ran on body + meta_desc + social.{bluesky, linkedin, twitter}
  • Temporal-trigger sweep: ran (recency words present in diff; spot-check in-review)
  • Code execution: not run (no static/programs/ change)
  • Code-examples checks: ran (3 specialists: structural, existence, body-code-coverage); 0 findings
  • Editorial-balance pass: ran (8 H2 sections, 1 flags fired)
🚨 Outstanding ⚠️ Low-confidence 💡 Pre-existing ✅ Resolved
0 12 0 2

🔍 Verification trail

73 claims extracted · 39 verified · 6 unverifiable · 3 contradicted
  • L3 in content/blog/ai-agents-on-kubernetes/index.md "date: 2026-07-28" → ➖ not-a-claim (evidence: A front-matter publication-date field set by the author, not a falsifiable factual assertion.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L5 in content/blog/ai-agents-on-kubernetes/index.md "How to provision and govern Kubernetes infrastructure for AI agents with Pulumi … where kagent, KServe, Kueue, and Neo fit in." → ➖ not-a-claim (evidence: A garbled extraction of the post's own summary describing its own content, not a third-party assertion.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L23 in content/blog/ai-agents-on-kubernetes/index.md "CNCF's 2026 annual survey found that 66% of organizations are betting on/plan to run Kubernetes for generative AI workloads." (also L27, L36) → ✅ verified (evidence: CNCF's January 2026 Annual Cloud Native Survey found "66% of organizations hosting generative AI models use Kubernetes to manage some or all of their inference workloads"; the 66% figure and CNCF 2026 attribution are accurate, though "betting on/plan to run" slightly shifts the source's current-usage framing.; source: https://www.cncf.io/announcements/2026/01/20/kubernetes-established-as-the-de-facto-operating-system-for-ai-as-production-use-hits-82-in-2025-cncf-annual-cloud-native-survey/)
  • L25 in content/blog/ai-agents-on-kubernetes/index.md "This post explains how to provision and govern AI agent infrastructure with Pulumi." (also L40) → ➖ not-a-claim (evidence: A self-description of the post's own purpose, not a falsifiable third-party assertion.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L27 in content/blog/ai-agents-on-kubernetes/index.md "An ecosystem including kagent, KServe, Kueue, vLLM/llm-d, and the Gateway API Inference Extension has grown up around running agents and models on Kubernetes." → ✅ verified (evidence: Multiple sources confirm KServe, Kueue, vLLM, llm-d, and the Gateway API Inference Extension are all active projects forming an ecosystem for running AI inference/agents on Kubernetes.; source: https://kserve.github.io/website/docs/model-serving/generative-inference/llmisvc/llmisvc-overview; https://kubernetes.io/blog/2025/06/05/introducing-gateway-api-inference-extension/)
  • L29 in content/blog/ai-agents-on-kubernetes/index.md "An AI agent has a blast radius that's very different from a typical Kubernetes Deployment." → ➖ not-a-claim (evidence: A subjective rhetorical comparison used to motivate the argument, not a falsifiable assertion.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L29 in content/blog/ai-agents-on-kubernetes/index.md "An AI agent requires credentials for whatever it's allowed to touch." → ➖ not-a-claim (evidence: A general common-sense statement about agent architecture, not a specific falsifiable product claim.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L31 in content/blog/ai-agents-on-kubernetes/index.md "The post covers where policy-as-code, secrets management, and Pulumi Neo fit into provisioning and governing AI agent infrastructure with Pulumi." → ✅ verified (evidence: The post's own body and LinkedIn copy state it covers provisioning and governing that infrastructure with Pulumi "plus where policy-as-code, secrets management, and Pulumi Neo fit in."; source: repo:content/blog/ai-agents-on-kubernetes/index.md)
  • L33 in content/blog/ai-agents-on-kubernetes/index.md "An AI agent on Kubernetes involves GPUs, long-lived sessions, and a much bigger credential blast radius than a typical Deployment." → ➖ not-a-claim (evidence: A qualitative editorial characterization of agent workloads, not a specific falsifiable assertion.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L36 in content/blog/ai-agents-on-kubernetes/index.md "CNCF's 2026 annual survey found that 66% of organizations are betting on Kubernetes to run their generative AI workloads." → ✅ verified (evidence: CNCF's Jan 20, 2026 announcement states "66% of organizations hosting generative AI models use Kubernetes to manage some or all of their inference workloads," matching the 66% figure.; source: https://www.cncf.io/announcements/2026/01/20/kubernetes-established-as-the-de-facto-operating-system-for-ai-as-production-use-hits-82-in-2025-cncf-annual-cloud-native-survey/)
  • L36 in content/blog/ai-agents-on-kubernetes/index.md "An AI agent is not a stateless web service." → ➖ not-a-claim (evidence: A rhetorical framing statement from the author's argument, not a falsifiable assertion.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L36 in content/blog/ai-agents-on-kubernetes/index.md "Provisioning infrastructure for an AI agent takes more than copying a Deployment YAML and swapping the image." → ➖ not-a-claim (evidence: An editorial/opinion statement framing the post's argument, not a falsifiable assertion.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L40 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi supports Kubernetes infrastructure provisioning using TypeScript and Python." → ✅ verified (evidence: The get-started Kubernetes page's language chooser includes typescript, python, go, csharp, java, yaml — TypeScript and Python are among the supported languages, so the claim is a narrower subset of the source's broader list.; source: repo:content/docs/iac/get-started/kubernetes/_index.md)
  • L40 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi Neo fits into the picture once the infrastructure itself has to answer to an agent." → ➖ not-a-claim (evidence: The author's own editorial positioning statement, elaborated later in the same post.; source: repo:content/blog/ai-agents-on-kubernetes/index.md)
  • L40 in content/blog/ai-agents-on-kubernetes/index.md "I spend a lot of my time these days thinking about what changes when the thing consuming your infrastructure isn't a person or a fixed pipeline, but an agent…" → ➖ not-a-claim (evidence: The author's own opinion/framing linking to the get-started page as context; the linked page exists and is a valid Kubernetes IaC tutorial.; source: repo:content/docs/iac/get-started/kubernetes/_index.md)
  • L44 in content/blog/ai-agents-on-kubernetes/index.md "An agent's resource and governance profile looks nothing like a typical web service because it schedules accelerators, holds state across long sessions, and reaches out to systems a normal Deployment never touches." → ➖ not-a-claim (evidence: A subjective editorial characterization, not a specific falsifiable assertion tied to a checkable source.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L46-53 in content/blog/ai-agents-on-kubernetes/index.md "Compared to a typical web service, an agent workload's credential surface includes API keys for one or more model providers plus whatever tools/MCP servers the agent is allowed to call…" → 🤷 unverifiable (evidence: A general conceptual comparison not tied to a citation; industry sources support the underlying idea but none states this exact comparison. Reads as the author's own illustration.; source: WebSearch ran query "AI agent credential surface API keys MCP servers security compared to web service"; results support general theme but no exact source for the specific comparison claim)
  • L55 in content/blog/ai-agents-on-kubernetes/index.md "Kubernetes's scheduler, autoscaling, and RBAC primitives are the right building blocks for running AI agent workloads." → ➖ not-a-claim (evidence: An opinion/positioning statement about Kubernetes's suitability, not a falsifiable assertion.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L59 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi's job is to provision and govern the infrastructure underneath agentic-Kubernetes tools, not to replace them." → ➖ not-a-claim (evidence: A first-party positioning statement about Pulumi's own product philosophy, not a third-party assertion.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L63-65 in content/blog/ai-agents-on-kubernetes/index.md "kagent is a framework for running AI agents on Kubernetes, with its own MCP server and CRDs for agents and model providers." (also L260-261) → ✅ verified (evidence: The kagent.dev homepage describes it as a "Kubernetes-native agent runtime" and lists "MCP Tool Servers" and "Agents as CRDs," confirming the framework, MCP server, and CRD claims.; source: https://kagent.dev/)
  • L65 in content/blog/ai-agents-on-kubernetes/index.md "Kueue provides job queueing for batch and ML workloads." → ✅ verified (evidence: Source states "Kubernetes-native Job Queueing … for batch, HPC, and AI/ML workloads" — the claim is a narrower subset of the source's broader form.; source: https://kueue.sigs.k8s.io/)
  • L66 in content/blog/ai-agents-on-kubernetes/index.md "KubeRay runs Ray (and Ray Serve) clusters on Kubernetes." → ✅ verified (evidence: The GitHub repo description states "A toolkit to run Ray applications on Kubernetes," consistent with the claim.; source: https://github.com/ray-project/kuberay)
  • L67 in content/blog/ai-agents-on-kubernetes/index.md "vLLM and llm-d together provide high-throughput, Kubernetes-native distributed LLM inference, and llm-d was launched by Red Hat as a community project." → 🤷 unverifiable (evidence: The fetched llm-d.ai homepage was truncated and did not contain any statement about the project's launch or Red Hat attribution; only deployment-recipe and version info were visible.; source: https://llm-d.ai/)
  • L68 in content/blog/ai-agents-on-kubernetes/index.md "LeaderWorkerSet and JobSet are multi-node inference and batch training workload APIs maintained under kubernetes-sigs." → ✅ verified (evidence: The kubernetes-sigs/lws repo confirms "LeaderWorkerSet: An API for deploying a group of pods as a unit of replication"; JobSet is a similarly-named kubernetes-sigs project for batch/ML training.; source: https://github.com/kubernetes-sigs/lws)
  • L69-70 in content/blog/ai-agents-on-kubernetes/index.md "Dynamic Resource Allocation (DRA) reached general availability in Kubernetes v1.34, which was released in September 2025." (also L262) → ❌ contradicted (evidence: DRA core did graduate to GA in v1.34, but v1.34 was released August 27, 2025, not September — the official release blog spans "19th May 2025 to 27th August 2025." The DRA feature article dated Sept 1, 2025 is an article publish date, not the release date.; source: https://kubernetes.io/blog/2025/08/27/kubernetes-v1-34-release/) — fixed in 36a9c960e3b: footnote now reads "released August 27, 2025," matching this source.
  • L70 in content/blog/ai-agents-on-kubernetes/index.md "The Gateway API Inference Extension provides routing and load balancing tuned for LLM inference traffic." → ✅ verified (evidence: Source states it "provides optimized routing and load balancing for serving Kubernetes self-hosted generative AI workloads," directly supporting the claim.; source: https://gateway-api-inference-extension.sigs.k8s.io/)
  • L71 in content/blog/ai-agents-on-kubernetes/index.md "The NVIDIA GPU Operator manages NVIDIA drivers and device plugins on cluster nodes." → ✅ verified (evidence: Repo description states "NVIDIA GPU Operator creates, configures, and manages GPUs in Kubernetes," which encompasses managing drivers and device plugins as claimed.; source: https://github.com/NVIDIA/gpu-operator)
  • L73 in content/blog/ai-agents-on-kubernetes/index.md "kagent defines its own custom resources named Agent, ModelConfig, ModelProviderConfig, RemoteMCPServer, and SandboxAgent." (also L263) → ✅ verified (evidence: The kagent API reference lists exactly these CRDs under kagent.dev/v1alpha2: Agent, ModelConfig, ModelProviderConfig, RemoteMCPServer, SandboxAgent.; source: https://docs.solo.io/kagent/main/reference/api/kagent/)
  • L73 in content/blog/ai-agents-on-kubernetes/index.md "kagent does not itself address how the cluster it runs on was provisioned, who is allowed to change it, or how secrets get to it safely." → ➖ not-a-claim (evidence: The author's own editorial framing of kagent's scope used to motivate the post's thesis, consistent with kagent's documented purpose.; source: repo:content/blog/ai-agents-on-kubernetes/index.md)
  • L80 in content/blog/ai-agents-on-kubernetes/index.md "kagent CRDs and its controller can be installed onto a cluster using a Pulumi Helm chart resource." → ✅ verified (evidence: The post's own TypeScript example uses new kubernetes.helm.v4.Chart("kagent-crds", …) and a second Chart for kagent itself; helm.v4.Chart is a real resource in the pulumi-kubernetes provider.; source: repo:content/blog/ai-agents-on-kubernetes/index.md)
  • L81 in content/blog/ai-agents-on-kubernetes/index.md "A model provider's API key can be stored as a Pulumi secret sourced from a Pulumi ESC environment rather than a plaintext Kubernetes Secret." → ➖ not-a-claim (evidence: The author's own design recommendation illustrated with their own code sample (config.requireSecret) — a standard, documented Pulumi ESC/secrets pattern.; source: repo:content/blog/ai-agents-on-kubernetes/index.md)
  • L84 in content/blog/ai-agents-on-kubernetes/index.md "The Pulumi Kubernetes Operator allows the cluster itself to reconcile against a Pulumi stack." → ✅ verified (evidence: The pulumi-kubernetes-operator repo is "A Kubernetes Operator that automates the deployment of Pulumi Stacks" and implements a StackReconciler via a controller-runtime Reconcile loop.; source: gh search code --owner pulumi -R pulumi/pulumi-kubernetes-operator "reconcile"; gh api repos/pulumi/pulumi-kubernetes-operator)
  • L86 in content/blog/ai-agents-on-kubernetes/index.md "Steps 1–4 in TypeScript:" → ➖ not-a-claim (evidence: A section heading/label describing the structure of the code walkthrough, not a falsifiable assertion.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L94-100 in content/blog/ai-agents-on-kubernetes/index.md "The eks.ManagedNodeGroup resource accepts cluster, nodeRole, instanceTypes, gpu, and scalingConfig properties." → ✅ verified (evidence: pulumi-eks schema.json and examples confirm ManagedNodeGroup accepts cluster, nodeRole, and gpu; instanceTypes and scalingConfig are standard EKS NodeGroup arguments used throughout the repo's examples.; source: gh api repos/pulumi/pulumi-eks/contents/provider/cmd/pulumi-resource-eks/schema.json; gh search code --owner pulumi repo:pulumi/pulumi-eks ManagedNodeGroup gpu)
  • L97 in content/blog/ai-agents-on-kubernetes/index.md "The example uses the AWS instance type g6.8xlarge for GPU-enabled nodes." (also L155) → ✅ verified (evidence: g6.8xlarge is a real AWS EC2 GPU instance (32 vCPUs, 128 GiB RAM, 1× NVIDIA L4).; source: https://cloudprice.net/aws/ec2/instances/g6.8xlarge)
  • L107-110 in content/blog/ai-agents-on-kubernetes/index.md "The kubernetes.helm.v4.Chart resource can install a Helm chart from an OCI registry reference such as oci://ghcr.io/kagent-dev/kagent/helm/kagent-crds." → ✅ verified (evidence: pulumi-kubernetes helm.v4.Chart docs document OCI support ("By OCI registry: chart: oci://…"), with multiple real oci:// examples across pulumi repos.; source: gh search code --owner pulumi "helm.v4.Chart oci://" (pulumi/pulumi-kubernetes sdk/nodejs/helm/v4/chart.ts))
  • L131-140 in content/blog/ai-agents-on-kubernetes/index.md "The kubernetes.apiextensions.CustomResource resource supports specifying apiVersion, kind, metadata, and spec to declare a kagent Agent custom resource with apiVersion: kagent.dev/v1alpha2." (also L184-186) → ✅ verified (evidence: Pulumi's CustomResource API accepts ApiVersion, Kind, Metadata, and Spec; kagent docs show Agent CRDs with apiVersion: kagent.dev/v1alpha2.; source: https://kagent.dev/docs/kagent/examples/a2a-byo and https://www.pulumi.com/registry/packages/kubernetes/api-docs/apiextensions/customresource/)
  • L203 in content/blog/ai-agents-on-kubernetes/index.md "CRD APIs, including kagent's kagent.dev/v1alpha2 group/version, may change faster than blog posts are updated, so readers should verify the exact CRD group/version against kagent's own manifests before shipping to production." → ✅ verified (evidence: kagent-dev/kagent confirms current CRDs use apiVersion kagent.dev/v1alpha2; the claim is an accurate "verify before shipping" caveat.; source: gh search code --owner kagent-dev "kagent.dev/v1alpha2")
  • L205 in content/blog/ai-agents-on-kubernetes/index.md "## Why write agent infrastructure in a general-purpose language instead of templated YAML?" → ➖ not-a-claim (evidence: A section heading phrased as a rhetorical question, the author's framing device.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L207 in content/blog/ai-agents-on-kubernetes/index.md "General-purpose languages such as TypeScript, Python, Go, C#, and Java natively support conditional logic, loops, and unit testing for infrastructure code, in ways that are bolted-on at best in Helm templates or raw manifests." → ➖ not-a-claim (evidence: A subjective comparative/opinion statement (Pulumi's standard "use real languages" value proposition), not a checkable factual assertion.; source: N/A - editorial/opinion claim)
  • L209 in content/blog/ai-agents-on-kubernetes/index.md "kagent's own install is distributed as a Helm chart." → ✅ verified (evidence: kagent-dev/kagent ships a Helm chart at helm/kagent/ and docs show helm install kagent oci://ghcr.io/kagent-dev/kagent/helm/kagent.; source: gh search code --repo kagent-dev/kagent "kagent helm")
  • L209 in content/blog/ai-agents-on-kubernetes/index.md "Helm and Kustomize remain genuinely good tools for packaging and distributing charts." → ➖ not-a-claim (evidence: A subjective positioning/opinion statement about Helm and Kustomize, not a falsifiable assertion.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L215 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi Policies let users write policy rules in general-purpose languages, rather than a separate policy DSL, that run before a change is applied." → ✅ verified (evidence: The policy docs state policies "can be written in TypeScript/JavaScript (Node.js), Python, or OPA (Rego)" and validate resources during preview/up, "blocking deployments when violations are detected" — i.e. before a change is applied.; source: repo:content/docs/insights/policy/_index.md)
  • L216 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi ESC is used for secrets and configuration so model-provider API keys and other credentials are centrally managed, rotated, and scoped." → ✅ verified (evidence: ESC docs describe "centralized secrets management and orchestration," dynamic imports, short-lived OIDC credentials (scoping), and rotation-supporting integrations — matching the claim.; source: repo:content/docs/esc/_index.md)
  • L217 in content/blog/ai-agents-on-kubernetes/index.md "The same custom-resource pattern used to declare an agent can also be used to declare its ServiceAccount, Role, and RoleBinding as code." → ➖ not-a-claim (evidence: The author's own architectural assertion about their example — a standard use of the @pulumi/kubernetes SDK, not a third-party factual claim.; source: repo:content/blog/ai-agents-on-kubernetes/index.md)
  • L219 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi Insights provides a searchable inventory of resources across Pulumi, Terraform, CloudFormation, and manually created infrastructure." → ✅ verified (evidence: Insights docs state Pulumi Cloud provides visibility "whether resources were provisioned by Pulumi, Terraform, CloudFormation, or created manually," with a "Resource search" feature.; source: repo:content/docs/insights/_index.md)
  • L219 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi Insights provides policy enforcement, including pre-built compliance packs." (also L245) → ✅ verified (evidence: The pricing page lists under Pulumi Insights both "Policy enforcement" and "Pre-built policy packs" (Pulumi Best Practices, CIS, NIST, HITRUST, PCI DSS).; source: repo:content/pricing/_index.md (lines ~516-543))
  • L219 in content/blog/ai-agents-on-kubernetes/index.md "Cost-optimization recommendations are a Pulumi Neo capability, not a Pulumi Insights capability." → 🤷 unverifiable (evidence: Verification did not converge on a source for this product-boundary claim within the allotted turns.; source: verify-claims.py)
  • L222-223 in content/blog/ai-agents-on-kubernetes/index.md "Documented Pulumi Neo capabilities include answering questions about existing infrastructure, proposing changes and opening a pull request for them, running a preview before changes land, reviewing PRs, and taking on recurring maintenance work." (also L225, L264-265) → ✅ verified (evidence: Pulumi's /docs/ai/neo/ pages confirm each capability: opens PRs for code modifications, proposes PRs after previews, reviews every PR by default, and runs recurring scheduled automations.; source: gh_query: pulumi/docs content/docs/ai/neo/*.md)
  • L225 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi's own product blog has described Neo containerizing and migrating a service onto Kubernetes." → ✅ verified (evidence: The "Ten More Things You Can Do With Pulumi Neo" blog describes Neo "migrating a VM-based service to Kubernetes step by step, following the team's Confluence runbook."; source: https://www.pulumi.com/blog/10-more-things-you-can-do-with-neo/)
  • L225 in content/blog/ai-agents-on-kubernetes/index.md "Every Pulumi Neo capability starts human-in-the-loop and only gains more autonomy once guardrails have proven themselves in practice." → ✅ verified (evidence: A direct paraphrase of the post's own first-party statement: "every capability starts human-in-the-loop and only earns more autonomy once the guardrails have proven themselves in practice."; source: repo:content/blog/ai-agents-on-kubernetes/index.md (line 225))
  • L227 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi Neo can propose a PR that adds a new GPU node pool." → ✅ verified (evidence: Neo docs confirm "Every change Neo proposes goes through a PR"; a GPU node-pool PR is a specific instance of the documented general capability.; source: gh search code --owner pulumi "Neo propose" (pulumi/docs:content/docs/ai/neo/pull-requests/_index.md))
  • L227 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi Neo can review a policy-pack change that locks down a RemoteMCPServer." → ✅ verified (evidence: Neo docs describe it reviewing and proposing IaC code changes; reviewing a policy-pack change is a specific instance of the documented PR-review capability.; source: repo:content/docs/ai/_index.md and repo:content/blog/ai-agents-on-kubernetes/index.md)
  • L227 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi Neo can handle maintenance toil around keeping an agentic Kubernetes stack current." → ✅ verified (evidence: Neo's documented capabilities include "taking on recurring maintenance work using your team's established Pulumi practices," which the claim faithfully restates.; source: repo:content/blog/ai-agents-on-kubernetes/index.md (L223, L227))
  • L227 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi Neo operates one layer up from workload-level agent frameworks, on the infrastructure that provisions and governs the cluster itself, rather than replacing kagent, KServe, or other frameworks." → ➖ not-a-claim (evidence: The author's own editorial positioning of Neo versus workload-level frameworks, a design/positioning statement about Pulumi's own product.; source: repo:content/blog/ai-agents-on-kubernetes/index.md)
  • L233 in content/blog/ai-agents-on-kubernetes/index.md "Using Pulumi to deploy AI agents on Kubernetes means the cluster, the runtime install, the secrets, and the agent definition are all one reviewable, testable stack rather than a mix of manually run kubectl apply commands." → ❌ contradicted (evidence: A positioning/opinion statement describing the author's own product design rationale, not a falsifiable third-party claim.; source: content/blog/ai-agents-on-kubernetes/index.md L233)
  • L233 in content/blog/ai-agents-on-kubernetes/index.md "kagent is the most Kubernetes-native agent-runtime option as of 2026." → ❌ contradicted (evidence: kagent.dev describes kagent as "Kubernetes-native agent runtime" but makes no comparative "most" claim against other runtimes; the superlative is a self-description-turned-ranking with no supporting source.; source: https://kagent.dev/) — fixed in 36a9c960e3b: now reads "one of the more Kubernetes-native options," which kagent's self-description supports.
  • L237 in content/blog/ai-agents-on-kubernetes/index.md "An agent that only calls a hosted model API such as OpenAI or Anthropic needs only CPU nodes to run its own logic and tool calls, since the GPU-heavy work happens on the provider's infrastructure." → 🤷 unverifiable (evidence: A general architectural statement (not a Pulumi product claim), consistent with how hosted inference APIs work but with no authoritative source to verify the exact framing against.; source: repo:content/blog/ai-agents-on-kubernetes/index.md)
  • L237 in content/blog/ai-agents-on-kubernetes/index.md "GPUs are needed once self-hosting inference, such as running an open-weight model via vLLM, KServe, or Ray Serve." → ➖ not-a-claim (evidence: A general industry-knowledge statement about ML infrastructure, not a Pulumi-specific falsifiable claim.; source: content/blog/ai-agents-on-kubernetes/index.md)
  • L241 in content/blog/ai-agents-on-kubernetes/index.md "A plain Kubernetes Deployment does not provide a standard way to describe an agent's model configuration, tool access, or MCP server connections as first-class, versionable objects." → ✅ verified (evidence: An accurate technical statement paraphrasing the post's adjacent text: the core Deployment/PodSpec has no schema fields for agent concepts, which is why kagent defines separate CRDs.; source: repo:content/blog/ai-agents-on-kubernetes/index.md (L240-241))
  • L241 in content/blog/ai-agents-on-kubernetes/index.md "kagent's CRDs (Agent, ModelConfig, ModelProviderConfig, RemoteMCPServer, SandboxAgent) exist specifically to make agent concepts declarative." → ✅ verified (evidence: All five CRDs confirmed in kagent-dev/kagent source (sandboxagent_types.go, remotemcpserver_types.go, modelproviderconfig_types.go, plus Agent/ModelConfig CRD YAML).; source: gh search code --owner kagent-dev "SandboxAgent" / "RemoteMCPServer" / "ModelProviderConfig" in kagent-dev/kagent)
  • L245 in content/blog/ai-agents-on-kubernetes/index.md "kubernetes.yaml.v2.ConfigFile and ConfigGroup can adopt existing manifests directly into a Pulumi program." → ✅ verified (evidence: Pulumi Kubernetes docs confirm ConfigFile "creates a set of Kubernetes resources from a remote or on-disk Kubernetes YAML file" and ConfigGroup for in-memory YAML — the adopt-existing-manifests behavior described.; source: gh api repos/pulumi/pulumi-kubernetes/contents/provider/pkg/gen/examples/overlays/configFileV2.md)
  • L245 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi Insights discovers and inventories Kubernetes resources regardless of what provisioned them, including Pulumi, Terraform, CloudFormation, or manual changes." → ✅ verified (evidence: Docs state Insights "scans your connected cloud accounts to build a searchable inventory of resources—including resources that were not created or managed by Pulumi," and enforcement works "regardless of how the resources were provisioned."; source: pulumi/docs:content/docs/iac/guides/basics/pulumi-cloud-vs-oss.md)
  • L249 in content/blog/ai-agents-on-kubernetes/index.md "Kueue can be used as a queueing layer for batch and training jobs so they don't starve latency-sensitive agent traffic." → ✅ verified (evidence: Kueue docs describe managing "quotas and resource sharing for batch, HPC, and AI/ML workloads" and deciding "when and where jobs should run," supporting the queueing-layer claim.; source: https://kueue.sigs.k8s.io/)
  • L253 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi Neo can answer questions about the state of a cluster, propose infrastructure changes as a reviewable pull request, run a preview before anything is applied, review incoming PRs, and take on recurring maintenance." → ✅ verified (evidence: The Neo docs page lists exactly these capabilities: answers questions, proposes changes via PR, runs previews, reviews PRs, and takes on recurring maintenance.; source: repo:content/docs/ai/neo/_index.md)
  • L257 in content/blog/ai-agents-on-kubernetes/index.md "the [Kubernetes get-started guide] and the Kubernetes provider registry cover the provisioning basics this post builds on." → ✅ verified (evidence: The cited registry URL returns HTTP 200 and is the Kubernetes provider registry page with provider details and per-resource docs.; source: https://www.pulumi.com/registry/packages/kubernetes/)
  • L259 in content/blog/ai-agents-on-kubernetes/index.md "The CNCF Annual Survey Report was published in January 2026." → ✅ verified (evidence: The cited PDF URL returns HTTP 200 and its path contains "/wp-content/uploads/2026/01/", corroborating the January 2026 timing.; source: https://www.cncf.io/wp-content/uploads/2026/01/CNCF_Annual_Survey_Report_final.pdf)
  • L260-261 in content/blog/ai-agents-on-kubernetes/index.md "KServe was accepted as a CNCF Incubating project on September 29, 2025, per CNCF's blog post dated November 11, 2025." → ❌ contradicted (evidence: The cited source URL (cncf.io/projects/kagent/) is the CNCF page for kagent, a different project; the fetched page shows only "kagent | CNCF" with no mention of KServe, so it does not support the claim.; source: https://www.cncf.io/projects/kagent/)
  • L262 in content/blog/ai-agents-on-kubernetes/index.md "Dynamic Resource Allocation reached general availability in Kubernetes v1.34, released in September 2025." → 🤷 unverifiable (evidence: The cited URL is the generic kubernetes.io/blog/ index page, which lists recent titles but contains no v1.34/DRA release detail; fetched 200 but no supporting passage.; source: https://kubernetes.io/blog/) — same footnote as the L69-70 finding above; fixed in 36a9c960e3b.
  • L263 in content/blog/ai-agents-on-kubernetes/index.md "kagent's CRD kinds (Agent, ModelConfig, ModelProviderConfig, RemoteMCPServer, SandboxAgent) are defined per the kagent-dev/kagent v1alpha2 API types." → 🤷 unverifiable (evidence: The fetched page was only the GitHub repo landing page (title/nav); the actual v1alpha2 Go type definitions live deeper in the repo and were not fetched.; source: https://github.com/kagent-dev/kagent)
  • L264-265 in content/blog/ai-agents-on-kubernetes/index.md "Pulumi's blog published a post titled '10 More Things You Can Do with Neo' describing Neo capabilities." → ✅ verified (evidence: The docs repo links "10 More Things You Can Do with Pulumi Neo" at /blog/10-more-things-you-can-do-with-neo/, and the post's own footnote cites the same URL.; source: repo:content/blog/the-agentic-infrastructure-era/index.md and repo:content/blog/ai-agents-on-kubernetes/index.md footnote [^neo-things])
  • L79-84 in content/blog/ai-agents-on-kubernetes/index.md "6. Roll changes out through CI, or through the Pulumi Kubernetes Operator" → 🚩 flagged (readthrough: missing-step)
  • L213-217 in content/blog/ai-agents-on-kubernetes/index.md "Three pieces of the Pulumi platform apply directly:" → 🚩 flagged (readthrough: missing-step)

📊 Editorial balance

Section depth, mention distribution, recommendation steering
  • Section depth: 8 H2 sections (mean 19.8 lines, median 9.0, std 32.4). Outliers: How do you provision Kubernetes infrastructure for AI agents with Pulumi?: 105 (11.7× median).
  • Vendor / entity mentions: Pulumi products (Neo, ESC, Insights, Policies, Kubernetes Operator) carry the recommendation weight, as expected for a first-party Pulumi post. Third-party ecosystem projects — kagent, KServe, Kueue, KubeRay, vLLM/llm-d, LeaderWorkerSet/JobSet, DRA, Gateway API Inference Extension, NVIDIA GPU Operator — are presented as first-class in the stack table, consistent with the post's stated "provision underneath, don't replace" framing. No competitor (Helm, Kustomize, Terraform, CloudFormation) is disparaged.
  • FAQ steering: 6 FAQ entries. Steering is Pulumi-forward (provisioning/governance → Pulumi; runtime → kagent; infra layer → Neo), which is expected for a single-vendor blog and does not artificially suppress the ecosystem tools — no single-entity steering threshold is tripped.

🚨 Outstanding in this PR

No outstanding findings in this PR.

⚠️ Low-confidence

Review each and resolve as appropriate — these don't block the PR.

  • [L46-53] content/blog/ai-agents-on-kubernetes/index.md — the credential-surface table row ("API keys for one or more model providers, plus whatever tools/MCP servers the agent is allowed to call") couldn't be confirmed against an external source; it reads as your own illustrative generalization, which is fine. Only act if you intend it as an assertion of fact — then add a citation.

  • [L67] content/blog/ai-agents-on-kubernetes/index.md"llm-d … Red Hat-launched, community project" couldn't be confirmed from llm-d.ai (the fetched page didn't cover the project's origin). Worth a quick source check on the Red Hat attribution before publish.

  • [L219] content/blog/ai-agents-on-kubernetes/index.md"Cost-optimization recommendations are a Neo capability, not an Insights one" couldn't be pinned to a source. As a first-party statement about Pulumi's own product boundaries it's low-risk, but a docs link (to the relevant Neo or Insights capability page) would make it checkable for readers.

  • [L237] content/blog/ai-agents-on-kubernetes/index.md"An agent that only calls a hosted model API … needs CPU nodes … the GPU-heavy work happens on the provider's infrastructure" is a general architectural statement with no external citation. It's consistent with how hosted inference APIs work but wasn't independently confirmed; no change needed unless you want to source it.

  • [L79-84] content/blog/ai-agents-on-kubernetes/index.md — the numbered list promises six steps, but the walkthrough that follows is explicitly scoped to "Steps 1–4 in TypeScript" — steps 5 (attach a policy pack) and 6 (roll out via CI or the Kubernetes Operator) never get a code example. That's a defensible scope for a blog post, and both are discussed in prose later (Pulumi Policies for step 5, the Operator link for step 6). Consider a one-line pointer after the code (e.g. "Steps 5–6 are covered in the governance section below") so a reader following the list knows the code intentionally stops at step 4. (Author: intentional editorial choice — offered to expand the walkthrough to inline steps 5–6 as code if wanted.)

  • [L213-217] content/blog/ai-agents-on-kubernetes/index.md — step 5 of the earlier procedure ("Attach a policy pack") is fulfilled here only as an abstract bullet, not the code a reader who reached step 5 might expect. Optional: add a short policy-pack snippet, or cross-reference back to step 5 so the two sections connect.

Style findings

Found by pattern-based linting; Findings may be false positives.

Click each filename to expand.

content/blog/ai-agents-on-kubernetes/index.md (6 issues: 2 difficulty qualifier, 2 weasel word, 2 wordiness)
  • line 215: [style] difficulty qualifier — Avoid difficulty qualifier 'just' -- it judges difficulty for the reader (STYLE-GUIDE.md §Inclusive Language).
  • line 259: [style] difficulty qualifier — Avoid difficulty qualifier 'just' -- it judges difficulty for the reader (STYLE-GUIDE.md §Inclusive Language).
  • line 38: [style] weasel word — 'usually' is a weasel word!
  • line 46: [style] weasel word — 'largely' is a weasel word!
  • line 61: [style] wordiness — 'it is' is too wordy.
  • line 209: [style] wordiness — 'all of' is too wordy.

📋 Triaged verifier findings

I double-checked these and realized they weren't real findings — click to expand
  • [L260-261] content/blog/ai-agents-on-kubernetes/index.md"KServe was accepted as a CNCF Incubating project on September 29, 2025, per CNCF's blog post dated November 11, 2025." Spurious: the verification step fetched CNCF's kagent project page (cncf.io/projects/kagent/) instead of the KServe incubation blog post the footnote actually cites, so the "contradiction" reflects checking the wrong page, not a real discrepancy. The KServe acceptance date hasn't been independently confirmed here — a quick author glance at the cited KServe post is worthwhile — but this is not a verified contradiction.

  • [L262] content/blog/ai-agents-on-kubernetes/index.md"Dynamic Resource Allocation reached general availability in Kubernetes v1.34, released in September 2025." Mis-sourced: the verification step fetched the generic kubernetes.io/blog/ index page, which can't confirm the claim. The real release-date discrepancy for this same statement was captured as a confirmed finding above — now fixed in 36a9c960e3b (v1.34 released August 27, 2025).

  • [L263] content/blog/ai-agents-on-kubernetes/index.md"kagent's CRD kinds (Agent, ModelConfig, ModelProviderConfig, RemoteMCPServer, SandboxAgent) are defined per the kagent-dev/kagent v1alpha2 API types." Mis-sourced: the verification step fetched only the GitHub repo landing page. The same CRD kinds are independently confirmed elsewhere in this trail (the kagent API reference and a source search of kagent-dev/kagent), so the claim holds.

💡 Pre-existing issues in touched files (optional)

No pre-existing issues in touched files.

✅ Resolved since last review

  • [L69-70] content/blog/ai-agents-on-kubernetes/index.md — the Kubernetes v1.34 release date in footnote [^dra-ga] was corrected from "September 2025" to "August 27, 2025," matching the official Kubernetes release blog. Fixed in 36a9c960e3b.

  • [L233] content/blog/ai-agents-on-kubernetes/index.md — the unsupported superlative "kagent is the most Kubernetes-native option as of 2026" was softened to "kagent is one of the more Kubernetes-native options as of 2026." Fixed in 36a9c960e3b.

📜 Review history

  • 2026-07-29T00:52:22Z — New blog post + additive HowTo-schema template changes; found a wrong Kubernetes v1.34 release date and an unsupported "most Kubernetes-native" superlative (both 🚨), plus 4 unverifiable claims and a code walkthrough that stops at step 4 of 6. (04bc9da)
  • 2026-07-29T01:25:00Z — re-reviewed after fix push (1 new commit, 36a9c960e3b): both outstanding findings resolved (v1.34 release date corrected, kagent superlative softened); swept the file for missed duplicates of "September 2025" and "most Kubernetes-native" — none found. Same commit also splits the Bluesky social copy into two paragraphs, addressing an unrelated social-review-bot flag.

Need a re-review? Want to dispute a finding? Mention @claude and include #update-review.
(For ad-hoc questions or fixes, just @claude — no hashtag.)

@github-actions

Copy link
Copy Markdown
Contributor

🤖 Review regenerated on @joeduffy's request.

@github-actions github-actions Bot added review:outstanding-issues Claude review completed; outstanding has author-actionable findings and removed review:in-progress Claude review is currently running labels Jul 29, 2026
…ften unsupported kagent superlative, split Bluesky copy into two paragraphs
@github-actions github-actions Bot added review:stale New commits since last Claude review; refresh on next ready-transition or @claude mention and removed review:outstanding-issues Claude review completed; outstanding has author-actionable findings labels Jul 29, 2026
@joeduffy

Copy link
Copy Markdown
Member Author

Thanks for the review — fixed both outstanding findings plus the Bluesky social-copy issue the social-review bot flagged separately:

  • [L262] Corrected the Dynamic Resource Allocation GA footnote: Kubernetes v1.34 released August 27, 2025, not September 2025 as originally written. (commit 36a9c960e3b)
  • [L233] Softened the unsupported "kagent is the most Kubernetes-native option" superlative to "one of the more Kubernetes-native options" — no source backs an absolute ranking claim. (commit 36a9c960e3b)
  • Split the Bluesky social copy into two paragraphs at the existing sentence boundary (221/300 chars), per the social-review bot's suggested minimum-change repair. (commit 36a9c960e3b)

Grepped the whole file for "September 2025" and "most Kubernetes-native" afterward — no other occurrences of either issue.

The step-4-of-6 code walkthrough note and the unverifiable-claims list are accurate as flagged; I left those as-is since they're editorial/low-confidence notes rather than factual errors, but happy to expand the walkthrough if you'd like the last two steps inlined as code rather than prose.

@joeduffy this is ready for your review/approval whenever you have a moment — @claude #update-review

@github-actions github-actions Bot added review:in-progress Claude review is currently running and removed review:stale New commits since last Claude review; refresh on next ready-transition or @claude mention labels Jul 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Review updated on @joeduffy's request.

@github-actions github-actions Bot added review:no-blockers Claude review completed cleanly; outstanding is empty and removed review:in-progress Claude review is currently running labels Jul 29, 2026
The 66% figure and the CNCF 2026 attribution were both correct, but the
framing around them overstated the finding in three ways: the denominator
widened from organizations already hosting generative AI models to
organizations generally, present-tense usage became future intent ("plan
to run" / "betting on"), and "some or all of their inference workloads"
became "their generative AI workloads."

CNCF's actual wording: "66% of organizations hosting generative AI models
use Kubernetes to manage some or all of their inference workloads."

Corrected in the opening paragraph and in the X and LinkedIn social copy,
which auto-post on merge. Bluesky doesn't cite the statistic. X copy is
236 chars, down from 243, so it stays inside the limit the earlier trim
established.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions github-actions Bot added review:stale New commits since last Claude review; refresh on next ready-transition or @claude mention and removed review:no-blockers Claude review completed cleanly; outstanding is empty labels Jul 30, 2026
@CamSoper
CamSoper enabled auto-merge (squash) July 30, 2026 01:37
@CamSoper
CamSoper merged commit 1050e9c into master Jul 30, 2026
11 checks passed
@CamSoper
CamSoper deleted the blog/ai-agents-on-kubernetes branch July 30, 2026 01:41
@github-actions

Copy link
Copy Markdown
Contributor

📣 Social media posts are live for https://www.pulumi.com/blog/ai-agents-on-kubernetes/:

CamSoper pushed a commit to CamSoper/pulumi.docs that referenced this pull request Jul 30, 2026
…p escalation, SHA-based review freshness

Gap 1 — no verdict for "value correct, meaning drifted" (PR pulumi#20550: three
stacked framing distortions on an accurate 66% CNCF figure rendered as
verified, with the drift observation buried in evidence prose):
- New `framing-drift` (🌀) verdict across verify-claims.py, compose-review.py,
  validate-pinned.py (schema v18→v19), splicer.py, validator-fix.py,
  record-claims.py (kept), reverify-claims.py (stale), compose-pr-body.py.
- Structured `framing` enum on verify_claim (exact-match / entailed-narrower /
  overclaim-broader / shifted / none); _finalize_verdict deterministically
  coerces a verified verdict carrying a drift shape to framing-drift, so the
  observation can no longer soft-pedal into verified prose.
- Framing taxonomy recast in entailment terms ("does the source, as quoted,
  prove the claim as written?") and reconciled across claim-extraction.md,
  fact-check.md (whose fallback section previously mapped the same labels to
  opposite verdicts), and the verifier prompt.
- Bucket: ⚠️ Low-confidence by default; reviewer promotes to 🚨 when the
  drifted phrasing rides social.* frontmatter (auto-posted on merge).
- New source-discipline rule: the content under review never verifies its own
  technical claims (the AES256-GCM circular-verification case on PR pulumi#20371).

Gap 2 — pass1 turn-cap and routing failures reported as unverifiable
(PR pulumi#20556: six REST-API claims died at the 8-turn cap; PR pulumi#20371: a pure
CLI-behavior claim routed to web search, which cannot read product source):
- pass1 turn cap 8→12; cap exhaustion now auto-escalates once to pass3
  instead of returning bare unverifiable.
- Symmetric route escalation: pass3 verifiers may emit
  route_escalation: "pass1" for Pulumi-product-behavior claims that carry no
  pulumi-shaped token (one hop, ping-pong guarded).
- Terminal turn-cap records carry `turn_cap_exhausted: true` and retryable
  phrasing; compose-review stubs them with an explicit "never call this out
  of scope" TODO so budget failures and architectural limits can no longer
  render identically downstream.

Gap 3 — stale pinned review kept review:no-blockers (PR pulumi#20556: a Copilot
conflict-resolution push fired no pull_request:synchronize event, so
mark-stale never ran; App pushes like workprentice[bot] do fire it — the
suppressed class is Copilot-agent and GITHUB_TOKEN pushes):
- compose-review.py stamps a machine-readable
  `<!-- CLAUDE_REVIEW_HEAD <sha> -->` sentinel under the review header
  (the workflow already passes --head-sha); update.md requires the
  re-entrant path to refresh it.
- pr-review SKILL Step 2 now runs a SHA freshness check before trusting
  CURRENT labels, with a review-history fallback for pre-sentinel reviews.
- New scheduled review-label-reconcile.yml workflow compares each labeled
  open PR's reviewed SHA against its head and applies the same stale
  transition mark-stale would have applied — the polling-side net for
  pushes that suppress webhook events.

Tests: new test_framing_drift.py (36 checks: constant sync, coercion,
escalation hops, cap marker, stub placement, validator acceptance/violation
directions, header sentinel); all existing docs-review and content-review
suites pass; make lint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KcNQVWHUyvbbe5Go9MGxwA
CamSoper pushed a commit that referenced this pull request Jul 30, 2026
…p escalation, SHA-based review freshness

Gap 1 — no verdict for "value correct, meaning drifted" (PR #20550: three
stacked framing distortions on an accurate 66% CNCF figure rendered as
verified, with the drift observation buried in evidence prose):
- New `framing-drift` (🌀) verdict across verify-claims.py, compose-review.py,
  validate-pinned.py (schema v18→v19), splicer.py, validator-fix.py,
  record-claims.py (kept), reverify-claims.py (stale), compose-pr-body.py.
- Structured `framing` enum on verify_claim (exact-match / entailed-narrower /
  overclaim-broader / shifted / none); _finalize_verdict deterministically
  coerces a verified verdict carrying a drift shape to framing-drift, so the
  observation can no longer soft-pedal into verified prose.
- Framing taxonomy recast in entailment terms ("does the source, as quoted,
  prove the claim as written?") and reconciled across claim-extraction.md,
  fact-check.md (whose fallback section previously mapped the same labels to
  opposite verdicts), and the verifier prompt.
- Bucket: ⚠️ Low-confidence by default; reviewer promotes to 🚨 when the
  drifted phrasing rides social.* frontmatter (auto-posted on merge).
- New source-discipline rule: the content under review never verifies its own
  technical claims (the AES256-GCM circular-verification case on PR #20371).

Gap 2 — pass1 turn-cap and routing failures reported as unverifiable
(PR #20556: six REST-API claims died at the 8-turn cap; PR #20371: a pure
CLI-behavior claim routed to web search, which cannot read product source):
- pass1 turn cap 8→12; cap exhaustion now auto-escalates once to pass3
  instead of returning bare unverifiable.
- Symmetric route escalation: pass3 verifiers may emit
  route_escalation: "pass1" for Pulumi-product-behavior claims that carry no
  pulumi-shaped token (one hop, ping-pong guarded).
- Terminal turn-cap records carry `turn_cap_exhausted: true` and retryable
  phrasing; compose-review stubs them with an explicit "never call this out
  of scope" TODO so budget failures and architectural limits can no longer
  render identically downstream.

Gap 3 — stale pinned review kept review:no-blockers (PR #20556: a Copilot
conflict-resolution push fired no pull_request:synchronize event, so
mark-stale never ran; App pushes like workprentice[bot] do fire it — the
suppressed class is Copilot-agent and GITHUB_TOKEN pushes):
- compose-review.py stamps a machine-readable
  `<!-- CLAUDE_REVIEW_HEAD <sha> -->` sentinel under the review header
  (the workflow already passes --head-sha); update.md requires the
  re-entrant path to refresh it.
- pr-review SKILL Step 2 now runs a SHA freshness check before trusting
  CURRENT labels, with a review-history fallback for pre-sentinel reviews.
- New scheduled review-label-reconcile.yml workflow compares each labeled
  open PR's reviewed SHA against its head and applies the same stale
  transition mark-stale would have applied — the polling-side net for
  pushes that suppress webhook events.

Tests: new test_framing_drift.py (36 checks: constant sync, coercion,
escalation hops, cap marker, stub placement, validator acceptance/violation
directions, header sentinel); all existing docs-review and content-review
suites pass; make lint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KcNQVWHUyvbbe5Go9MGxwA
CamSoper added a commit that referenced this pull request Jul 30, 2026
…p escalation, SHA-based review freshness (#20577)

* Close three docs-review pipeline gaps: framing-drift verdict, turn-cap escalation, SHA-based review freshness

Gap 1 — no verdict for "value correct, meaning drifted" (PR #20550: three
stacked framing distortions on an accurate 66% CNCF figure rendered as
verified, with the drift observation buried in evidence prose):
- New `framing-drift` (🌀) verdict across verify-claims.py, compose-review.py,
  validate-pinned.py (schema v18→v19), splicer.py, validator-fix.py,
  record-claims.py (kept), reverify-claims.py (stale), compose-pr-body.py.
- Structured `framing` enum on verify_claim (exact-match / entailed-narrower /
  overclaim-broader / shifted / none); _finalize_verdict deterministically
  coerces a verified verdict carrying a drift shape to framing-drift, so the
  observation can no longer soft-pedal into verified prose.
- Framing taxonomy recast in entailment terms ("does the source, as quoted,
  prove the claim as written?") and reconciled across claim-extraction.md,
  fact-check.md (whose fallback section previously mapped the same labels to
  opposite verdicts), and the verifier prompt.
- Bucket: ⚠️ Low-confidence by default; reviewer promotes to 🚨 when the
  drifted phrasing rides social.* frontmatter (auto-posted on merge).
- New source-discipline rule: the content under review never verifies its own
  technical claims (the AES256-GCM circular-verification case on PR #20371).

Gap 2 — pass1 turn-cap and routing failures reported as unverifiable
(PR #20556: six REST-API claims died at the 8-turn cap; PR #20371: a pure
CLI-behavior claim routed to web search, which cannot read product source):
- pass1 turn cap 8→12; cap exhaustion now auto-escalates once to pass3
  instead of returning bare unverifiable.
- Symmetric route escalation: pass3 verifiers may emit
  route_escalation: "pass1" for Pulumi-product-behavior claims that carry no
  pulumi-shaped token (one hop, ping-pong guarded).
- Terminal turn-cap records carry `turn_cap_exhausted: true` and retryable
  phrasing; compose-review stubs them with an explicit "never call this out
  of scope" TODO so budget failures and architectural limits can no longer
  render identically downstream.

Gap 3 — stale pinned review kept review:no-blockers (PR #20556: a Copilot
conflict-resolution push fired no pull_request:synchronize event, so
mark-stale never ran; App pushes like workprentice[bot] do fire it — the
suppressed class is Copilot-agent and GITHUB_TOKEN pushes):
- compose-review.py stamps a machine-readable
  `<!-- CLAUDE_REVIEW_HEAD <sha> -->` sentinel under the review header
  (the workflow already passes --head-sha); update.md requires the
  re-entrant path to refresh it.
- pr-review SKILL Step 2 now runs a SHA freshness check before trusting
  CURRENT labels, with a review-history fallback for pre-sentinel reviews.
- New scheduled review-label-reconcile.yml workflow compares each labeled
  open PR's reviewed SHA against its head and applies the same stale
  transition mark-stale would have applied — the polling-side net for
  pushes that suppress webhook events.

Tests: new test_framing_drift.py (36 checks: constant sync, coercion,
escalation hops, cap marker, stub placement, validator acceptance/violation
directions, header sentinel); all existing docs-review and content-review
suites pass; make lint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KcNQVWHUyvbbe5Go9MGxwA

* Count framing-drift separately from contradicted in the headline tallies

The first cut folded framing-drift into CONTRADICTION_FAMILY, which feeds the
🔍 trail <details> header and the investigation log's parenthetical — both of
which label that number `contradicted`. But framing-drift defaults to ⚠️, not
🚨, so the headline reported contradictions the body didn't contain: a fork run
produced `2 verified · 0 unverifiable · 2 contradicted` above a trail with zero
❌ lines, and another read `4 contradicted` for 1 real ❌ plus 3 🌀.

CONTRADICTION_FAMILY now means what its name says (contradicted + mismatch) and
drift gets its own `· W framing-drift` segment in both places, omitted entirely
when the count is zero so ordinary reviews are byte-identical. The per-lane
Pass 2/3 V/C/U triple keeps drift in the C column — that triple's shape is
pinned by validate-pinned.py's PASS2_OUTCOME_RE/PASS3_OUTCOME_RE, and it's a
routing diagnostic rather than a reader-facing count.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review:stale New commits since last Claude review; refresh on next ready-transition or @claude mention

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants