Skip to content

Commit a0dbcdf

Browse files
authored
Merge pull request #227 from kagent-dev/peterj/addextblogs
add external blog posts
2 parents 00c510f + 193ace2 commit a0dbcdf

3 files changed

Lines changed: 134 additions & 13 deletions

File tree

CONTRIBUTION.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ The kagent website includes a blog section where we post about kagent. If you'd
8585
- Posts should focus on the open source kagent project and not vendor specific projects or products
8686
- Any submitted blog posts must be original content and not a copy of existing blog posts
8787

88-
### Submitting a blog post
88+
### Writing a new blog post on kagent
8989

9090
1. Create your blog post in `src/blogContent` folder. You can copy an existing blog post and modify it.
9191
2. Make sure you add the following metadata at the top of your blog post - update the title, published date, description, author, and authorIds accordingly.
@@ -124,6 +124,10 @@ If you need to add a new author, you can do that in the [authors.ts file](https:
124124

125125
4. All images can be added to the public/images folder.
126126

127+
### Adding an existing blog post
128+
129+
To add an existing blog post, you can add a new entry into the `external-blog-posts.yaml` file. Same guidelines as above apply.
130+
127131
## Style Guide
128132

129133
- Follow the existing code style

src/app/blog/page.tsx

Lines changed: 108 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import { Background } from "@/components/background";
22
import Link from "next/link";
33
import React from "react";
4+
import externalPostsData from "@/data/external-blog-posts.yaml";
5+
import { Badge } from "@/components/ui/badge";
6+
import { Button } from "@/components/ui/button";
7+
import { getAuthorById, type Author } from "./authors";
8+
import { DISCORD_LINK, GITHUB_LINK } from "@/data/links";
9+
import Discord from "@/components/icons/discord";
10+
import Github from "@/components/icons/github";
411

512
function shortDate(date: string) {
613
return new Date(date).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
@@ -12,33 +19,61 @@ const posts = [
1219
publishDate: '2025-09-09',
1320
title: "Truly Reactive Cloud Native AI Agents with Kagent and Khook",
1421
description: "Khook makes Kagent Agents Reactive",
22+
authorId: "antweiss",
1523
},
1624
{
1725
slug: 'ai-reliability-aire',
1826
publishDate: '2025-05-14',
1927
title: 'AI Reliability Engineering For More Dependable Humans',
2028
description: 'AI Reliability Engineering (AIRE) brings AI agents to SRE and Platform Engineering workflows for dependable humans.',
29+
authorId: "christianposta",
2130
},
2231
{
2332
slug: 'kgateway-guardrails',
2433
publishDate: '2025-05-19',
2534
title: 'Adding Guardrails to kagent with kgateway AI Gateway',
2635
description: 'Adding guardrails, observability, and security to Agent to LLM communication with an AI gateway like kgateway',
36+
authorId: "christianposta",
2737
},
2838
{
2939
slug: 'kagent-celebrating-100-days',
3040
publishDate: '2025-07-01',
3141
title: 'Celebrating 100 Days of Kagent',
3242
description: '100+ contributors, 1000+ GitHub stars and more!',
43+
authorId: "linsun",
3344
},
3445
{
3546
slug: 'kmcp',
3647
publishDate: '2025-07-30',
3748
title: 'From MCP Servers to Services: Introducing kmcp for Enterprise-Grade MCP Development',
3849
description: 'Discover kmcp, the lightweight toolkit that takes MCP servers from prototype to production. Learn how to scaffold, build, and deploy enterprise-grade MCP services to Kubernetes in minutes—no Dockerfiles or complex manifests required. Includes demo video and complete getting started guide.',
50+
authorId: "christianposta",
3951
}
4052
]
4153

54+
type InternalPostCombined = {
55+
title: string;
56+
description: string;
57+
publishDate: string;
58+
href: string;
59+
isExternal: false;
60+
slug: string;
61+
author: Author | null;
62+
}
63+
64+
type ExternalPostCombined = {
65+
title: string;
66+
description: string;
67+
publishDate: string;
68+
href: string;
69+
isExternal: true;
70+
author: string; // Keep as string for external posts since they're not in our authors.ts
71+
}
72+
73+
type CombinedPost = InternalPostCombined | ExternalPostCombined;
74+
75+
type ExternalYamlPost = { title: string; description: string; publishDate: string; url: string; author: string };
76+
4277
export default async function BlogPage() {
4378
return (
4479
<>
@@ -47,20 +82,81 @@ export default async function BlogPage() {
4782
<div className="max-w-3xl mx-auto px-4">
4883
<h1 className="text-4xl font-bold text-center mb-16 text-foreground">Blog</h1>
4984
<div className="space-y-12 md:space-y-16">
50-
{posts.sort((a, b) => new Date(b.publishDate).getTime() - new Date(a.publishDate).getTime()).map((post) => (
51-
<div key={post.slug} className="py-4">
52-
<div className="flex items-center space-x-3 text-sm text-muted-foreground mb-2">
53-
<span>{shortDate(post.publishDate)}</span>
54-
</div>
55-
<div className="mt-5 text-3xl lg:text-4xl font-bold mb-3 text-foreground">
56-
<Link href={`/blog/${post.slug}`} className="hover:text-primary transition-colors duration-200">{post.title}</Link>
85+
{(() => {
86+
const internalPosts: InternalPostCombined[] = posts.map(p => ({
87+
title: p.title,
88+
description: p.description,
89+
publishDate: p.publishDate,
90+
href: `/blog/${p.slug}`,
91+
isExternal: false as const,
92+
slug: p.slug,
93+
author: getAuthorById(p.authorId) || null,
94+
}));
95+
const rawExternal: ExternalYamlPost[] = (externalPostsData && (externalPostsData as { externalPosts?: ExternalYamlPost[] }).externalPosts) || [];
96+
const externalPosts: ExternalPostCombined[] = rawExternal.map((p: ExternalYamlPost) => ({
97+
title: p.title,
98+
description: p.description,
99+
publishDate: p.publishDate,
100+
href: p.url,
101+
isExternal: true as const,
102+
author: p.author,
103+
}));
104+
const allPosts: CombinedPost[] = [...internalPosts, ...externalPosts].sort((a, b) => new Date(b.publishDate).getTime() - new Date(a.publishDate).getTime());
105+
return allPosts.map((post) => (
106+
<div key={post.isExternal ? post.href : post.slug} className="py-4">
107+
<div className="flex items-center space-x-3 text-sm text-muted-foreground mb-2">
108+
<span>{shortDate(post.publishDate)}</span>
109+
{post.isExternal && <Badge variant="default" className="bg-primary/10 text-primary border-primary/20 hover:bg-primary/20">External</Badge>}
110+
</div>
111+
<div className="mt-5 text-3xl lg:text-4xl font-bold mb-3 text-foreground">
112+
{post.isExternal ? (
113+
<a href={post.href} target="_blank" rel="noopener noreferrer" className="hover:text-primary transition-colors duration-200">{post.title}</a>
114+
) : (
115+
<Link href={post.href} className="hover:text-primary transition-colors duration-200">{post.title}</Link>
116+
)}
117+
</div>
118+
<div className="text-sm font-medium text-foreground/70 mb-4 italic">
119+
by {post.isExternal ? post.author : post.author ? `${post.author.name}, ${post.author.title}` : 'Unknown Author'}
120+
</div>
121+
<p className="text-muted-foreground mb-4 leading-relaxed text-lg font-normal">{post.description}</p>
122+
{post.isExternal ? (
123+
<a href={post.href} target="_blank" rel="noopener noreferrer" className="text-primary font-medium hover:underline text-sm inline-flex items-center">
124+
Read the post <span aria-hidden="true" className="ml-1"></span>
125+
</a>
126+
) : (
127+
<Link href={post.href} className="text-primary font-medium hover:underline text-sm inline-flex items-center">
128+
Read the post <span aria-hidden="true" className="ml-1"></span>
129+
</Link>
130+
)}
57131
</div>
58-
<p className="text-muted-foreground mb-4 leading-relaxed text-base">{post.description}</p>
59-
<Link href={`/blog/${post.slug}`} className="text-primary font-medium hover:underline text-sm inline-flex items-center">
60-
Read the post <span aria-hidden="true" className="ml-1"></span>
132+
));
133+
})()}
134+
</div>
135+
</div>
136+
137+
{/* Community Section */}
138+
<div className="py-16 border-t border-border">
139+
<div className="max-w-3xl mx-auto px-4 text-center">
140+
<h2 className="text-3xl font-medium mb-8 text-foreground">
141+
Join our <span className="text-primary font-semibold">community</span>
142+
</h2>
143+
<p className="text-lg text-muted-foreground mb-12 leading-relaxed">
144+
Connect with other developers, share your experiences, and get support from the kagent community.
145+
</p>
146+
<div className="flex justify-center space-x-6">
147+
<Button size="lg" className="text-base px-6 py-3">
148+
<Discord className="mr-2 h-5 w-5" />
149+
<Link href={DISCORD_LINK} target="_blank" rel="noopener noreferrer">
150+
Discord
151+
</Link>
152+
</Button>
153+
<Button size="lg" variant="outline" className="text-base px-6 py-3">
154+
<Github className="mr-2 h-5 w-5" />
155+
<Link href={GITHUB_LINK} target="_blank" rel="noopener noreferrer">
156+
GitHub
61157
</Link>
62-
</div>
63-
))}
158+
</Button>
159+
</div>
64160
</div>
65161
</div>
66162
</div>

src/data/external-blog-posts.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# External blog posts displayed on the blog index alongside internal posts
2+
# Fields: title, description, publishDate (YYYY-MM-DD), url, author
3+
externalPosts:
4+
- title: "KAgent: Open-Source Agentic AI Framework for Autonomous Systems"
5+
description: "KAgent is an open-source framework for building autonomous AI agents that can make decisions and perform tasks with minimal human oversight. Donated by Solo.io, it enables developers to create intelligent systems for virtual assistance, data processing, and workflow automation by leveraging generative AI and external API integrations."
6+
publishDate: "2025-05-19"
7+
url: "https://medium.com/@godhanipayal/kagent-open-source-agentic-ai-framework-for-autonomous-systems-cfde34a80742"
8+
author: "Payal Godhani"
9+
- title: "An Introduction to Kagent: The Open-Source Framework for AI Agents on Kubernetes"
10+
description: "The article talks about how kagent democratizes cloud-native expertise by packaging expert knowledge into AI agents that can troubleshoot, diagnose, and automatically fix Kubernetes issues, demonstrated through a real-world example where an agent identified and resolved a misconfigured service routing problem by creating a GitHub pull request."
11+
publishDate: "2025-08-15"
12+
url: "https://www.platformers.community/post/an-introduction-to-kagent-the-open-source-framework-for-ai-agents-on-kubernetes"
13+
author: "Guy Menahem"
14+
- title: "Exploring Argocd’s New Mcp Server With Kagent"
15+
description: "This technical walkthrough demonstrates how to integrate ArgoCD's new MCP (Model Context Protocol) Server with kagent, an AI agent framework for Kubernetes. The author shows step-by-step how to deploy kagent via ArgoCD, configure it with OpenAI integration, add ArgoCD's MCP server as a tool, and create an AI agent that can directly query and interact with ArgoCD applications - showcasing the potential for intelligent Kubernetes operations through AI-powered automation."
16+
publishDate: "2025-05-08"
17+
url: "https://chrismatcham.dev/Exploring-ArgoCD-s-New-MCP-Server-with-Kagent/"
18+
author: "Chris Matcham"
19+
20+
21+

0 commit comments

Comments
 (0)