feat(blogs): added blogs scaffolding (#1857)

This commit is contained in:
Waleed
2025-11-08 00:04:20 -08:00
committed by GitHub
parent c397f5acee
commit 945405c461
26 changed files with 1381 additions and 948 deletions

View File

@@ -0,0 +1,166 @@
import type { Metadata } from 'next'
import Image from 'next/image'
import Link from 'next/link'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { FAQ } from '@/lib/blog/faq'
import { getAllPostMeta, getPostBySlug, getRelatedPosts } from '@/lib/blog/registry'
import { buildArticleJsonLd, buildBreadcrumbJsonLd, buildPostMetadata } from '@/lib/blog/seo'
import { soehne } from '@/app/fonts/soehne/soehne'
export async function generateStaticParams() {
const posts = await getAllPostMeta()
return posts.map((p) => ({ slug: p.slug }))
}
export async function generateMetadata({
params,
}: {
params: Promise<{ slug: string }>
}): Promise<Metadata> {
const { slug } = await params
const post = await getPostBySlug(slug)
return buildPostMetadata(post)
}
export const revalidate = 86400
export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params
const post = await getPostBySlug(slug)
const Article = post.Content
const jsonLd = buildArticleJsonLd(post)
const breadcrumbLd = buildBreadcrumbJsonLd(post)
const related = await getRelatedPosts(slug, 3)
return (
<article
className={`${soehne.className} w-full`}
itemScope
itemType='https://schema.org/BlogPosting'
>
<script
type='application/ld+json'
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<script
type='application/ld+json'
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbLd) }}
/>
<header className='mx-auto max-w-[1450px] px-6 pt-8 sm:px-8 sm:pt-12 md:px-12 md:pt-16'>
<div className='mb-6'>
<Link href='/blog' className='text-gray-600 text-sm hover:text-gray-900'>
Back to Blog
</Link>
</div>
<div className='flex flex-col gap-8 md:flex-row md:gap-12'>
<div className='h-[180px] w-full flex-shrink-0 sm:h-[200px] md:h-auto md:w-[300px]'>
<div className='relative h-full w-full overflow-hidden rounded-lg md:aspect-[5/4]'>
<Image
src={post.ogImage}
alt={post.title}
width={300}
height={240}
className='h-full w-full object-cover'
priority
itemProp='image'
/>
</div>
</div>
<div className='flex flex-1 flex-col justify-between'>
<h1
className='font-medium text-[36px] leading-tight tracking-tight sm:text-[48px] md:text-[56px] lg:text-[64px]'
itemProp='headline'
>
{post.title}
</h1>
<div className='mt-4 flex items-center gap-3'>
{(post.authors || [post.author]).map((a, idx) => (
<div key={idx} className='flex items-center gap-2'>
{a?.avatarUrl ? (
<Avatar className='size-6'>
<AvatarImage src={a.avatarUrl} alt={a.name} />
<AvatarFallback>{a.name.slice(0, 2)}</AvatarFallback>
</Avatar>
) : null}
<Link
href={a?.url || '#'}
target='_blank'
rel='noopener noreferrer author'
className='text-[14px] text-gray-600 leading-[1.5] hover:text-gray-900 sm:text-[16px]'
itemProp='author'
itemScope
itemType='https://schema.org/Person'
>
<span itemProp='name'>{a?.name}</span>
</Link>
</div>
))}
</div>
</div>
</div>
<hr className='mt-8 border-gray-200 border-t sm:mt-12' />
<div className='flex flex-col gap-6 py-8 sm:flex-row sm:items-start sm:justify-between sm:gap-8 sm:py-10'>
<div className='flex flex-shrink-0 items-center gap-4'>
<time
className='block text-[14px] text-gray-600 leading-[1.5] sm:text-[16px]'
dateTime={post.date}
itemProp='datePublished'
>
{new Date(post.date).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})}
</time>
<meta itemProp='dateModified' content={post.updated ?? post.date} />
</div>
<div className='flex-1'>
<p className='m-0 block translate-y-[-4px] font-[400] text-[18px] leading-[1.5] sm:text-[20px] md:text-[26px]'>
{post.description}
</p>
</div>
</div>
</header>
<div className='mx-auto max-w-[900px] px-6 pb-20 sm:px-8 md:px-12' itemProp='articleBody'>
<div className='prose prose-lg max-w-none'>
<Article />
{post.faq && post.faq.length > 0 ? <FAQ items={post.faq} /> : null}
</div>
</div>
{related.length > 0 && (
<div className='mx-auto max-w-[900px] px-6 pb-24 sm:px-8 md:px-12'>
<h2 className='mb-4 font-medium text-[24px]'>Related posts</h2>
<div className='grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3'>
{related.map((p) => (
<Link key={p.slug} href={`/blog/${p.slug}`} className='group'>
<div className='overflow-hidden rounded-lg border border-gray-200'>
<Image
src={p.ogImage}
alt={p.title}
width={600}
height={315}
className='h-[160px] w-full object-cover'
/>
<div className='p-3'>
<div className='mb-1 text-gray-600 text-xs'>
{new Date(p.date).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})}
</div>
<div className='font-medium text-sm leading-tight'>{p.title}</div>
</div>
</div>
</Link>
))}
</div>
</div>
)}
<meta itemProp='publisher' content='Sim' />
<meta itemProp='inLanguage' content='en-US' />
<meta itemProp='keywords' content={post.tags.join(', ')} />
</article>
)
}

View File

@@ -0,0 +1,72 @@
import Image from 'next/image'
import Link from 'next/link'
import { getAllPostMeta } from '@/lib/blog/registry'
import { soehne } from '@/app/fonts/soehne/soehne'
export const revalidate = 3600
export default async function AuthorPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params
const posts = (await getAllPostMeta()).filter((p) => p.author.id === id)
const author = posts[0]?.author
if (!author) {
return (
<main className={`${soehne.className} mx-auto max-w-[900px] px-6 py-10 sm:px-8 md:px-12`}>
<h1 className='font-medium text-[32px]'>Author not found</h1>
</main>
)
}
const personJsonLd = {
'@context': 'https://schema.org',
'@type': 'Person',
name: author.name,
url: `https://sim.ai/blog/authors/${author.id}`,
sameAs: author.url ? [author.url] : [],
image: author.avatarUrl,
}
return (
<main className={`${soehne.className} mx-auto max-w-[900px] px-6 py-10 sm:px-8 md:px-12`}>
<script
type='application/ld+json'
dangerouslySetInnerHTML={{ __html: JSON.stringify(personJsonLd) }}
/>
<div className='mb-6 flex items-center gap-3'>
{author.avatarUrl ? (
<Image
src={author.avatarUrl}
alt={author.name}
width={40}
height={40}
className='rounded-full'
/>
) : null}
<h1 className='font-medium text-[32px] leading-tight'>{author.name}</h1>
</div>
<div className='grid grid-cols-1 gap-8 sm:grid-cols-2'>
{posts.map((p) => (
<Link key={p.slug} href={`/blog/${p.slug}`} className='group'>
<div className='overflow-hidden rounded-lg border border-gray-200'>
<Image
src={p.ogImage}
alt={p.title}
width={600}
height={315}
className='h-[160px] w-full object-cover transition-transform group-hover:scale-[1.02]'
/>
<div className='p-3'>
<div className='mb-1 text-gray-600 text-xs'>
{new Date(p.date).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})}
</div>
<div className='font-medium text-sm leading-tight'>{p.title}</div>
</div>
</div>
</Link>
))}
</div>
</main>
)
}

View File

@@ -0,0 +1,13 @@
export default function Head() {
return (
<>
<link rel='canonical' href='https://sim.ai/blog' />
<link
rel='alternate'
type='application/rss+xml'
title='Sim Blog'
href='https://sim.ai/blog/rss.xml'
/>
</>
)
}

View File

@@ -1,11 +1,40 @@
import { Footer, Nav } from '@/app/(landing)/components'
export default function BlogLayout({ children }: { children: React.ReactNode }) {
const orgJsonLd = {
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'Sim',
url: 'https://sim.ai',
logo: 'https://sim.ai/logo/primary/small.png',
sameAs: ['https://x.com/simdotai'],
}
const websiteJsonLd = {
'@context': 'https://schema.org',
'@type': 'WebSite',
name: 'Sim',
url: 'https://sim.ai',
potentialAction: {
'@type': 'SearchAction',
target: 'https://sim.ai/search?q={search_term_string}',
'query-input': 'required name=search_term_string',
},
}
return (
<>
<div className='flex min-h-screen flex-col'>
<script
type='application/ld+json'
dangerouslySetInnerHTML={{ __html: JSON.stringify(orgJsonLd) }}
/>
<script
type='application/ld+json'
dangerouslySetInnerHTML={{ __html: JSON.stringify(websiteJsonLd) }}
/>
<Nav hideAuthButtons={false} variant='landing' />
<main className='relative'>{children}</main>
<main className='relative flex-1'>{children}</main>
<Footer fullWidth={true} />
</>
</div>
)
}

View File

@@ -1,795 +0,0 @@
import Image from 'next/image'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { soehne } from '@/app/fonts/soehne/soehne'
export default function OpenAiN8nSim() {
const baseUrl = 'https://sim.ai'
const articleUrl = `${baseUrl}/blog/openai-vs-n8n-vs-sim`
const articleStructuredData = {
'@context': 'https://schema.org',
'@type': 'TechArticle',
headline: 'OpenAI AgentKit vs n8n vs Sim: AI Agent Workflow Builder Comparison',
description:
'Compare OpenAI AgentKit, n8n, and Sim for building AI agent workflows. Explore key differences in capabilities, integrations, collaboration, and which platform best fits your production AI agent needs.',
image: `${baseUrl}/blog/openai-vs-n8n-vs-sim/workflow.png`,
datePublished: '2025-10-06T00:00:00.000Z',
dateModified: '2025-10-06T00:00:00.000Z',
author: {
'@type': 'Person',
name: 'Emir Karabeg',
url: 'https://x.com/karabegemir',
sameAs: ['https://x.com/karabegemir'],
},
publisher: {
'@type': 'Organization',
name: 'Sim',
logo: {
'@type': 'ImageObject',
url: `${baseUrl}/logo/sim-logo.png`,
},
url: baseUrl,
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': articleUrl,
},
keywords:
'AI agents, OpenAI AgentKit, n8n, Sim, workflow automation, AI agent development, RAG, MCP protocol, agentic workflows, ChatKit, AI Copilot',
articleSection: 'Technology',
inLanguage: 'en-US',
about: [
{
'@type': 'Thing',
name: 'Artificial Intelligence',
},
{
'@type': 'Thing',
name: 'Workflow Automation',
},
{
'@type': 'SoftwareApplication',
name: 'OpenAI AgentKit',
},
{
'@type': 'SoftwareApplication',
name: 'n8n',
},
{
'@type': 'SoftwareApplication',
name: 'Sim',
},
],
}
const breadcrumbStructuredData = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{
'@type': 'ListItem',
position: 1,
name: 'Home',
item: baseUrl,
},
{
'@type': 'ListItem',
position: 2,
name: 'Blog',
item: `${baseUrl}/blog`,
},
{
'@type': 'ListItem',
position: 3,
name: 'OpenAI AgentKit vs n8n vs Sim',
item: articleUrl,
},
],
}
return (
<>
{/* Structured Data for SEO */}
<script
type='application/ld+json'
dangerouslySetInnerHTML={{
__html: JSON.stringify(articleStructuredData),
}}
/>
<script
type='application/ld+json'
dangerouslySetInnerHTML={{
__html: JSON.stringify(breadcrumbStructuredData),
}}
/>
<article
className={`${soehne.className} w-full`}
itemScope
itemType='https://schema.org/TechArticle'
>
{/* Header Section with Image and Title */}
<header className='mx-auto max-w-[1450px] px-6 pt-8 sm:px-8 sm:pt-12 md:px-12 md:pt-16'>
<div className='flex flex-col gap-8 md:flex-row md:gap-12'>
{/* Large Image on Left */}
<div className='h-[180px] w-full flex-shrink-0 sm:h-[200px] md:h-auto md:w-[300px]'>
<div className='relative h-full w-full overflow-hidden rounded-lg md:aspect-[5/4]'>
<Image
src='/blog/openai-vs-n8n-vs-sim/workflow.png'
alt='Sim AI agent workflow builder interface'
width={300}
height={240}
className='h-full w-full object-cover'
priority
itemProp='image'
/>
</div>
</div>
{/* Main Title - Taking up 80% */}
<div className='flex flex-1 flex-col justify-between'>
<h1
className='font-medium text-[36px] leading-tight tracking-tight sm:text-[48px] md:text-[56px] lg:text-[64px]'
itemProp='headline'
>
OpenAI AgentKit vs n8n vs Sim: AI Agent Workflow Builder Comparison
</h1>
<div className='mt-4 hidden items-center justify-end gap-2 sm:flex'>
<a
href='https://x.com/karabegemir'
target='_blank'
rel='noopener noreferrer author'
aria-label='@karabegemir on X'
className='block'
>
<Avatar className='size-6'>
<AvatarImage
src='/blog/openai-vs-n8n-vs-sim/emir-karabeg.png'
alt='Emir Karabeg'
/>
<AvatarFallback>EK</AvatarFallback>
</Avatar>
</a>
<a
href='https://x.com/karabegemir'
target='_blank'
rel='noopener noreferrer author'
className='text-[14px] text-gray-600 leading-[1.5] hover:text-gray-900 sm:text-[16px]'
itemProp='author'
itemScope
itemType='https://schema.org/Person'
>
<span itemProp='name'>Emir Karabeg</span>
</a>
</div>
</div>
</div>
{/* Horizontal Line Separator */}
<hr className='mt-8 border-gray-200 border-t sm:mt-12' />
{/* Publish Date and Subtitle */}
<div className='flex flex-col gap-6 py-8 sm:flex-row sm:items-start sm:justify-between sm:gap-8 sm:py-10'>
{/* Publish Date and Author */}
<div className='flex flex-shrink-0 items-center justify-between gap-4 sm:gap-0'>
<time
className='block text-[14px] text-gray-600 leading-[1.5] sm:text-[16px]'
dateTime='2025-10-06T00:00:00.000Z'
itemProp='datePublished'
>
Published Oct 6, 2025
</time>
<meta itemProp='dateModified' content='2025-10-06T00:00:00.000Z' />
<div className='flex items-center gap-2 sm:hidden'>
<a
href='https://x.com/karabegemir'
target='_blank'
rel='noopener noreferrer author'
aria-label='@karabegemir on X'
className='block'
>
<Avatar className='size-6'>
<AvatarImage
src='/blog/openai-vs-n8n-vs-sim/emir-karabeg.png'
alt='Emir Karabeg'
/>
<AvatarFallback>EK</AvatarFallback>
</Avatar>
</a>
<a
href='https://x.com/karabegemir'
target='_blank'
rel='noopener noreferrer author'
className='text-[14px] text-gray-600 leading-[1.5] hover:text-gray-900'
>
Emir Karabeg
</a>
</div>
</div>
{/* Subtitle on Right */}
<div className='flex-1'>
<p
className='m-0 block translate-y-[-4px] font-[400] text-[18px] leading-[1.5] sm:text-[20px] md:text-[26px]'
itemProp='description'
>
OpenAI just released AgentKit for building AI agents. How does it compare to
workflow automation platforms like n8n and purpose-built AI agent builders like Sim?
</p>
</div>
</div>
</header>
{/* Main Content Area - Medium-style centered with padding */}
<div className='mx-auto max-w-[800px] px-6 pb-20 sm:px-8 md:px-12' itemProp='articleBody'>
<div className='prose prose-lg max-w-none'>
{/* Introduction */}
<section className='mb-12'>
<p className='text-[20px] text-gray-800 leading-relaxed'>
When building AI agent workflows, developers often evaluate multiple platforms to
find the right fit for their needs. Three platforms frequently come up in these
discussions: OpenAI's new AgentKit, the established workflow automation tool n8n,
and Sim, a purpose-built AI agent workflow builder. While all three enable AI agent
development, they take fundamentally different approaches, each with distinct
strengths and ideal use cases.
</p>
</section>
{/* Section 1: OpenAI AgentKit */}
<section className='mb-12'>
<h2 className='mb-4 font-medium text-[28px] leading-tight sm:text-[32px]'>
What is OpenAI AgentKit?
</h2>
<p className='mb-6 text-[19px] text-gray-800 leading-relaxed'>
OpenAI AgentKit is a set of building blocks designed to help developers take AI
agents from prototype to production. Built on top of the OpenAI Responses API, it
provides a structured approach to building and deploying intelligent agents.
</p>
<figure className='my-8 overflow-hidden rounded-lg'>
<Image
src='/blog/openai-vs-n8n-vs-sim/openai.png'
alt='OpenAI AgentKit workflow interface'
width={800}
height={450}
className='w-full'
/>
<figcaption className='sr-only'>
OpenAI AgentKit visual workflow builder interface
</figcaption>
</figure>
<h3 className='mt-6 mb-3 font-medium text-[22px] leading-tight'>Core Features</h3>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Agent Builder Canvas
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
AgentKit provides a visual canvas where developers can design and build agents. This
interface allows you to model complex workflows visually, making it easier to
understand and iterate on agent behavior. The builder is powered by OpenAI's
Responses API.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
ChatKit for Embedded Interfaces
</h4>
<p className='mb-6 text-[19px] text-gray-800 leading-relaxed'>
ChatKit enables developers to embed chat interfaces to run workflows directly within
their applications. It includes custom widgets that you can create and integrate,
with the ability to preview interfaces right in the workflow builder before
deployment.
</p>
<figure className='my-8 overflow-hidden rounded-lg'>
<Image
src='/blog/openai-vs-n8n-vs-sim/widgets.png'
alt='OpenAI AgentKit custom widgets interface'
width={800}
height={450}
className='w-full'
/>
<figcaption className='sr-only'>
OpenAI AgentKit ChatKit custom widgets preview
</figcaption>
</figure>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Comprehensive Evaluation System
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
AgentKit includes out-of-the-box evaluation capabilities to measure agent
performance. Features include datasets to assess agent nodes, prompt optimization
tools, and the ability to run evaluations on external models beyond OpenAI's
ecosystem.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Connectors and Integrations
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
The platform provides connectors to integrate with both internal tools and external
services, enabling agents to interact with your existing tech stack.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>API Publishing</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
Once your agent is ready, the publish feature allows you to integrate it as an API
inside your codebase, making deployment straightforward.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Built-in Guardrails
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
AgentKit comes with guardrails out of the box, helping ensure agent behavior stays
within defined boundaries and safety parameters.
</p>
<h3 className='mt-6 mb-3 font-medium text-[22px] leading-tight'>
What AgentKit Doesn't Offer
</h3>
<p className='mb-2 text-[19px] text-gray-800 leading-relaxed'>
While AgentKit is powerful for building agents, it has some limitations:
</p>
<ul className='mb-4 ml-6 list-disc text-[19px] text-gray-800 leading-relaxed'>
<li className='mb-2'>
Only able to run OpenAI modelsno support for other AI providers
</li>
<li className='mb-2'>
Cannot make generic API requests in workflowslimited to MCP (Model Context
Protocol) integrations only
</li>
<li className='mb-2'>Not an open-source platform</li>
<li className='mb-2'>No workflow templates to accelerate development</li>
<li className='mb-2'>
No execution logs or detailed monitoring for debugging and observability
</li>
<li className='mb-2'>No ability to trigger workflows via external integrations</li>
<li className='mb-2'>
Limited out-of-the-box integration options compared to dedicated workflow
automation platforms
</li>
</ul>
</section>
{/* Section 2: n8n */}
<section className='mb-12'>
<h2 className='mb-4 font-medium text-[28px] leading-tight sm:text-[32px]'>
What is n8n?
</h2>
<p className='mb-6 text-[19px] text-gray-800 leading-relaxed'>
n8n is a workflow automation platform that excels at connecting various services and
APIs together. While it started as a general automation tool, n8n has evolved to
support AI agent workflows alongside its traditional integration capabilities.
</p>
<figure className='my-8 overflow-hidden rounded-lg'>
<Image
src='/blog/openai-vs-n8n-vs-sim/n8n.png'
alt='n8n workflow automation interface'
width={800}
height={450}
className='w-full'
/>
<figcaption className='sr-only'>
n8n node-based visual workflow automation platform
</figcaption>
</figure>
<h3 className='mt-6 mb-3 font-medium text-[22px] leading-tight'>Core Capabilities</h3>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Extensive Integration Library
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
n8n's primary strength lies in its vast library of pre-built integrations. With
hundreds of connectors for popular services, it makes it easy to connect disparate
systems without writing custom code.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Visual Workflow Builder
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
The platform provides a node-based visual interface for building workflows. Users
can drag and drop nodes representing different services and configure how data flows
between them.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Flexible Triggering Options
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
n8n supports various ways to trigger workflows, including webhooks, scheduled
executions, and manual triggers, making it versatile for different automation
scenarios.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
AI and LLM Integration
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
More recently, n8n has added support for AI models and agent-like capabilities,
allowing users to incorporate language models into their automation workflows.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Self-Hosting Options
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
n8n offers both cloud-hosted and self-hosted deployment options, giving
organizations control over their data and infrastructure.
</p>
<h3 className='mt-6 mb-3 font-medium text-[22px] leading-tight'>Primary Use Cases</h3>
<p className='mb-2 text-[19px] text-gray-800 leading-relaxed'>
n8n is best suited for:
</p>
<ul className='mb-4 ml-6 list-disc text-[19px] text-gray-800 leading-relaxed'>
<li className='mb-2'>Traditional workflow automation and service integration</li>
<li className='mb-2'>Data synchronization between business tools</li>
<li className='mb-2'>Event-driven automation workflows</li>
<li className='mb-2'>Simple AI-enhanced automations</li>
</ul>
<h3 className='mt-6 mb-3 font-medium text-[22px] leading-tight'>
What n8n Doesn't Offer
</h3>
<p className='mb-2 text-[19px] text-gray-800 leading-relaxed'>
While n8n is excellent for traditional automation, it has some limitations for AI
agent development:
</p>
<ul className='mb-4 ml-6 list-disc text-[19px] text-gray-800 leading-relaxed'>
<li className='mb-2'>
No SDK to build workflows programmaticallylimited to visual builder only
</li>
<li className='mb-2'>
Not fully open source but fair-use licensed, with some restrictions
</li>
<li className='mb-2'>
Free trial limited to 14 days, after which paid plans are required
</li>
<li className='mb-2'>Limited/complex parallel execution handling</li>
</ul>
</section>
{/* Section 3: Sim */}
<section className='mb-12'>
<h2 className='mb-4 font-medium text-[28px] leading-tight sm:text-[32px]'>
What is Sim?
</h2>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
Sim is a fully open-source platform (Apache 2.0 license) specifically designed for
AI agent development. Unlike platforms that added AI capabilities as an
afterthought, Sim was created from the ground up to address the unique challenges of
building, testing, and deploying production-ready AI agents.
</p>
<h3 className='mt-6 mb-3 font-medium text-[22px] leading-tight'>
Comprehensive AI Agent Platform
</h3>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Visual AI Workflow Builder
</h4>
<p className='mb-6 text-[19px] text-gray-800 leading-relaxed'>
Sim provides an intuitive drag-and-drop canvas where developers can build complex AI
agent workflows visually. The platform supports sophisticated agent architectures,
including multi-agent systems, conditional logic, loops, and parallel execution
paths. Additionally, Sim's built-in AI Copilot can assist you directly in the
editor, helping you build and modify workflows faster with intelligent suggestions
and explanations.
</p>
<figure className='my-8 overflow-hidden rounded-lg'>
<Image
src='/blog/openai-vs-n8n-vs-sim/sim.png'
alt='Sim visual workflow builder with AI agent blocks'
width={800}
height={450}
className='w-full'
/>
<figcaption className='sr-only'>
Sim drag-and-drop AI agent workflow builder canvas
</figcaption>
</figure>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
AI Copilot for Workflow Building
</h4>
<p className='mb-6 text-[19px] text-gray-800 leading-relaxed'>
Sim includes an intelligent in-editor AI assistant that helps you build and edit
workflows faster. Copilot can explain complex concepts, suggest best practices, and
even make changes to your workflow when you approve them. Using the @ context menu,
you can reference workflows, blocks, knowledge bases, documentation, templates, and
execution logs—giving Copilot the full context it needs to provide accurate,
relevant assistance. This dramatically accelerates workflow development compared to
building from scratch.
</p>
<figure className='my-8 overflow-hidden rounded-lg'>
<Image
src='/blog/openai-vs-n8n-vs-sim/copilot.png'
alt='Sim AI Copilot assisting with workflow development'
width={800}
height={450}
className='w-full'
/>
<figcaption className='sr-only'>
Sim AI Copilot in-editor assistant for workflow building
</figcaption>
</figure>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Pre-Built Workflow Templates
</h4>
<p className='mb-6 text-[19px] text-gray-800 leading-relaxed'>
Get started quickly with Sim's extensive library of pre-built workflow templates.
Browse templates across categories like Marketing, Sales, Finance, Support, and
Artificial Intelligence. Each template is a production-ready workflow you can
customize for your needs, saving hours of development time. Templates are created by
the Sim team and community members, with popularity ratings and integration counts
to help you find the right starting point.
</p>
<figure className='my-8 overflow-hidden rounded-lg'>
<Image
src='/blog/openai-vs-n8n-vs-sim/templates.png'
alt='Sim workflow templates gallery'
width={800}
height={450}
className='w-full'
/>
<figcaption className='sr-only'>
Sim pre-built workflow templates library
</figcaption>
</figure>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
80+ Built-in Integrations
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
Out of the box, Sim connects with 80+ services including multiple AI providers
(OpenAI, Anthropic, Google, Groq, Cerebras, local Ollama models), communication
tools (Gmail, Slack, Teams, Telegram, WhatsApp), productivity apps (Notion, Google
Sheets, Airtable, Monday.com), and developer tools (GitHub, GitLab).
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Multiple Trigger Options
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
Unlike AgentKit, Sim workflows can be triggered in multiple ways: chat interfaces,
REST APIs, webhooks, scheduled jobs, or external events from integrated services
like Slack and GitHub. This flexibility ensures your agents can be activated however
your use case demands.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Real-Time Team Collaboration
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
Sim enables multiple team members to work simultaneously on the same workflow with
real-time editing, commenting, and comprehensive permissions management. This makes
it ideal for teams building complex agent systems together.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Advanced Agent Capabilities
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
The platform includes specialized blocks for AI agents, RAG (Retrieval-Augmented
Generation) systems, function calling, code execution, data processing, and
evaluation. These purpose-built components enable developers to create sophisticated
agentic workflows without custom coding.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Intelligent Knowledge Base with Vector Search
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
Sim's native knowledge base goes far beyond simple document storage. Powered by
pgvector, it provides semantic search that understands meaning and context, not just
keywords. Upload documents in multiple formats (PDF, Word, Excel, Markdown, and
more), and Sim automatically processes them with intelligent chunking, generates
vector embeddings, and makes them instantly searchable. The knowledge base supports
natural language queries, concept-based retrieval, multi-language understanding, and
configurable chunk sizes (100-4,000 characters). This makes building RAG agents
straightforward—your AI can search through your organization's knowledge with
context-aware precision.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Comprehensive Execution Logging and Monitoring
</h4>
<p className='mb-6 text-[19px] text-gray-800 leading-relaxed'>
Sim provides enterprise-grade logging that captures every detail of workflow
execution. Track workflow runs with execution IDs, view block-level logs with
precise timing and duration metrics, monitor token usage and costs per execution,
and debug failures with detailed error traces and trace spans. The logging system
integrates with Copilotyou can reference execution logs directly in your Copilot
conversations to understand what happened and troubleshoot issues. This level of
observability is essential for production AI agents where understanding behavior and
debugging issues quickly is critical.
</p>
<figure className='my-8 overflow-hidden rounded-lg'>
<Image
src='/blog/openai-vs-n8n-vs-sim/logs.png'
alt='Sim execution logs and monitoring dashboard'
width={800}
height={450}
className='w-full'
/>
<figcaption className='sr-only'>
Sim execution logs dashboard with detailed workflow monitoring
</figcaption>
</figure>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Custom Integrations via MCP Protocol
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
Beyond the 80+ built-in integrations, Sim supports the Model Context Protocol (MCP),
allowing developers to create custom integrations for proprietary systems or
specialized tools.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Flexible Deployment Options
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
Sim offers both cloud-hosted and self-hosted deployment options. Organizations can
run Sim on their own infrastructure for complete control, or use the managed cloud
service for simplicity. The platform is SOC2 and HIPAA compliant, ensuring
enterprise-level security.
</p>
<h4 className='mt-4 mb-2 font-medium text-[19px] leading-tight'>
Production-Ready Infrastructure
</h4>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
The platform includes everything needed for production deployments: background job
processing, webhook handling, monitoring, and API management. Workflows can be
published as REST API endpoints, embedded via SDKs, or run through chat interfaces.
</p>
<h3 className='mt-6 mb-3 font-medium text-[22px] leading-tight'>
What You Can Build with Sim
</h3>
<ul className='mb-4 ml-6 list-disc text-[19px] text-gray-800 leading-relaxed'>
<li className='mb-2'>
<strong>AI Assistants & Chatbots:</strong> Intelligent agents that search the web,
access calendars, send emails, and interact with business tools
</li>
<li className='mb-2'>
<strong>Business Process Automation:</strong> Automate repetitive tasks like data
entry, report generation, customer support, and content creation
</li>
<li className='mb-2'>
<strong>Data Processing & Analysis:</strong> Extract insights from documents,
analyze datasets, generate reports, and sync data between systems
</li>
<li className='mb-2'>
<strong>API Integration Workflows:</strong> Connect multiple services into unified
endpoints and orchestrate complex business logic
</li>
<li className='mb-2'>
<strong>RAG Systems:</strong> Build sophisticated retrieval-augmented generation
pipelines with custom knowledge bases
</li>
</ul>
<h3 className='mt-6 mb-3 font-medium text-[22px] leading-tight'>
Drawbacks to Consider
</h3>
<p className='mb-2 text-[19px] text-gray-800 leading-relaxed'>
While Sim excels at AI agent workflows, there are some tradeoffs:
</p>
<ul className='mb-4 ml-6 list-disc text-[19px] text-gray-800 leading-relaxed'>
<li className='mb-2'>
Fewer pre-built integrations compared to n8n's extensive library—though Sim's 80+
integrations cover most AI agent use cases and MCP protocol enables custom
integrations
</li>
</ul>
</section>
{/* Comparison Section */}
<section className='mb-12'>
<h2 className='mb-4 font-medium text-[28px] leading-tight sm:text-[32px]'>
Key Differences
</h2>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
While all three platforms enable AI agent development, they excel in different
areas:
</p>
<h3 className='mt-6 mb-3 font-medium text-[22px] leading-tight'>OpenAI AgentKit</h3>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
<strong>Best for:</strong> Teams deeply invested in the OpenAI ecosystem who
prioritize evaluation and testing capabilities. Ideal when you need tight
integration with OpenAI's latest models and want built-in prompt optimization and
evaluation tools.
</p>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
<strong>Limitations:</strong> Locked into OpenAI models only, not open-source, no
workflow templates or execution logs, limited triggering options, and fewer
out-of-the-box integrations.
</p>
<h3 className='mt-6 mb-3 font-medium text-[22px] leading-tight'>n8n</h3>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
<strong>Best for:</strong> Traditional workflow automation with some AI enhancement.
Excellent when your primary need is connecting business tools and services, with AI
as a complementary feature rather than the core focus.
</p>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
<strong>Limitations:</strong> No SDK for programmatic workflow building, fair-use
licensing (not fully open source), 14-day trial limitation, and AI agent
capabilities are newer and less mature compared to its traditional automation
features.
</p>
<h3 className='mt-6 mb-3 font-medium text-[22px] leading-tight'>Sim</h3>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
<strong>Best for:</strong> Building production-ready AI agent workflows that require
flexibility, collaboration, and comprehensive tooling. Ideal for teams that need AI
Copilot assistance, advanced knowledge base features, detailed logging, and the
ability to work across multiple AI providers with purpose-built agentic workflow
tools.
</p>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
<strong>Limitations:</strong> Fewer integrations than n8n's extensive library,
though the 80+ built-in integrations and MCP protocol support cover most AI agent
needs.
</p>
</section>
{/* Conclusion */}
<section className='mb-12'>
<h2 className='mb-4 font-medium text-[28px] leading-tight sm:text-[32px]'>
Which Should You Choose?
</h2>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
The right platform depends on your specific needs and context:
</p>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
Choose <strong>OpenAI AgentKit</strong> if you're exclusively using OpenAI models
and want to build chat interfaces with the ChatKit. It's a solid choice for teams
that want to stay within OpenAI's ecosystem and prioritize testing capabilities.
</p>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
Choose <strong>n8n</strong> if your primary use case is traditional workflow
automation between business tools, with occasional AI enhancement. It's ideal for
organizations already familiar with n8n who want to add some AI capabilities to
existing automations.
</p>
<p className='mb-4 text-[19px] text-gray-800 leading-relaxed'>
Choose <strong>Sim</strong> if you're building AI agents as your primary objective
and need a platform purpose-built for that use case. Sim provides the most
comprehensive feature set for agentic workflows, with AI Copilot to accelerate
development, parallel execution handling, intelligent knowledge base for RAG
applications, detailed execution logging for production monitoring, flexibility
across AI providers, extensive integrations, team collaboration, and deployment
options that scale from prototype to production.
</p>
</section>
</div>
</div>
{/* Publisher information for schema */}
<meta itemProp='publisher' content='Sim' />
<meta itemProp='inLanguage' content='en-US' />
<meta
itemProp='keywords'
content='AI agents, OpenAI AgentKit, n8n, Sim, workflow automation'
/>
</article>
</>
)
}

View File

@@ -1,135 +0,0 @@
import type { Metadata } from 'next'
import OpenAiN8nSim from './openai-n8n-sim'
const baseUrl = 'https://sim.ai'
const canonicalUrl = `${baseUrl}/blog/openai-vs-n8n-vs-sim`
export const metadata: Metadata = {
title: 'OpenAI AgentKit vs n8n vs Sim: AI Agent Workflow Builder Comparison | Sim',
description:
'Compare OpenAI AgentKit, n8n, and Sim for building AI agent workflows. Explore key differences in capabilities, integrations, collaboration, and which platform best fits your production AI agent needs.',
keywords: [
'AgentKit',
'AI agents',
'AI agent development',
'agents',
'workflow builder',
'visual workflow builder',
'workflows',
'OpenAI AgentKit',
'OpenAI',
'OpenAI Responses API',
'n8n',
'n8n workflow automation',
'AI workflow automation',
'workflow automation platform',
'Sim',
'agent builder comparison',
'RAG agents',
'RAG systems',
'retrieval augmented generation',
'ChatKit',
'agent evaluation',
'prompt optimization',
'multi-agent systems',
'team collaboration workflows',
'production AI agents',
'AI guardrails',
'workflow integrations',
'self-hosted AI agents',
'cloud AI agent platform',
'MCP protocol',
'Model Context Protocol',
'knowledge base integration',
'vector embeddings',
'AI agent canvas',
'agentic workflows',
'AI agent API',
'AI chatbot workflows',
'business process automation',
'AI Copilot',
'workflow copilot',
'AI assistant for workflows',
'vector search',
'semantic search',
'pgvector',
'knowledge base AI',
'document embeddings',
'execution logging',
'workflow monitoring',
'AI agent observability',
'workflow debugging',
'execution traces',
'AI workflow logs',
'intelligent chunking',
'context-aware search',
],
authors: [{ name: 'Emir Karabeg', url: 'https://x.com/karabegemir' }],
creator: 'Emir Karabeg',
publisher: 'Sim',
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
alternates: {
canonical: canonicalUrl,
},
openGraph: {
title: 'OpenAI AgentKit vs n8n vs Sim: AI Agent Workflow Builder Comparison',
description:
'Compare OpenAI AgentKit, n8n, and Sim for building AI agent workflows. Explore key differences in capabilities, integrations, and which platform fits your production needs.',
url: canonicalUrl,
siteName: 'Sim',
locale: 'en_US',
type: 'article',
publishedTime: '2025-10-06T00:00:00.000Z',
modifiedTime: '2025-10-06T00:00:00.000Z',
authors: ['Emir Karabeg'],
section: 'Technology',
tags: [
'AI Agents',
'Workflow Automation',
'OpenAI AgentKit',
'n8n',
'Sim',
'AgentKit',
'AI Development',
'RAG',
'MCP Protocol',
],
images: [
{
url: `${baseUrl}/blog/openai-vs-n8n-vs-sim/workflow.png`,
width: 1200,
height: 630,
alt: 'Sim AI agent workflow builder interface comparison',
},
],
},
twitter: {
card: 'summary_large_image',
title: 'OpenAI AgentKit vs n8n vs Sim: AI Agent Workflow Builder Comparison',
description:
'Compare OpenAI AgentKit, n8n, and Sim for building AI agent workflows. Explore key differences in capabilities, integrations, and which platform fits your production needs.',
images: ['/blog/openai-vs-n8n-vs-sim/workflow.png'],
creator: '@karabegemir',
site: '@simai',
},
other: {
'article:published_time': '2025-10-06T00:00:00.000Z',
'article:modified_time': '2025-10-06T00:00:00.000Z',
'article:author': 'Emir Karabeg',
'article:section': 'Technology',
},
}
export default function Page() {
return <OpenAiN8nSim />
}

View File

@@ -1,5 +1,223 @@
import { redirect } from 'next/navigation'
import Image from 'next/image'
import Link from 'next/link'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { getAllPostMeta } from '@/lib/blog/registry'
import { soehne } from '@/app/fonts/soehne/soehne'
export default function BlogPage() {
redirect('/blog/openai-vs-n8n-vs-sim')
export const revalidate = 3600
export default async function BlogIndex({
searchParams,
}: {
searchParams: Promise<{ page?: string; tag?: string }>
}) {
const { page, tag } = await searchParams
const pageNum = Math.max(1, Number(page || 1))
const perPage = 20
const all = await getAllPostMeta()
const filtered = tag ? all.filter((p) => p.tags.includes(tag)) : all
const totalPages = Math.max(1, Math.ceil(filtered.length / perPage))
const start = (pageNum - 1) * perPage
const posts = filtered.slice(start, start + perPage)
// Tag filter chips are intentionally disabled for now.
// const tags = await getAllTags()
const blogJsonLd = {
'@context': 'https://schema.org',
'@type': 'Blog',
name: 'Sim Blog',
url: 'https://sim.ai/blog',
description: 'Announcements, insights, and guides for building AI agent workflows.',
}
const [featured, ...rest] = posts
return (
<main className={`${soehne.className} mx-auto max-w-[1200px] px-6 py-12 sm:px-8 md:px-12`}>
<script
type='application/ld+json'
dangerouslySetInnerHTML={{ __html: JSON.stringify(blogJsonLd) }}
/>
<h1 className='mb-3 font-medium text-[40px] leading-tight sm:text-[56px]'>The Sim Times</h1>
<p className='mb-10 text-[18px] text-gray-700'>
Announcements, insights, and guides for building AI agent workflows.
</p>
{/* Tag filter chips hidden until we have more posts */}
{/* <div className='mb-10 flex flex-wrap gap-3'>
<Link href='/blog' className={`rounded-full border px-3 py-1 text-sm ${!tag ? 'border-black bg-black text-white' : 'border-gray-300'}`}>All</Link>
{tags.map((t) => (
<Link key={t.tag} href={`/blog?tag=${encodeURIComponent(t.tag)}`} className={`rounded-full border px-3 py-1 text-sm ${tag === t.tag ? 'border-black bg-black text-white' : 'border-gray-300'}`}>
{t.tag} ({t.count})
</Link>
))}
</div> */}
{featured && (
<Link href={`/blog/${featured.slug}`} className='group mb-10 block'>
<div className='overflow-hidden rounded-2xl border border-gray-200'>
<Image
src={featured.ogImage}
alt={featured.title}
width={1200}
height={630}
className='h-[320px] w-full object-cover sm:h-[420px]'
/>
<div className='p-6 sm:p-8'>
<div className='mb-2 text-gray-600 text-xs sm:text-sm'>
{new Date(featured.date).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})}
</div>
<h2 className='shine-text mb-2 font-medium text-2xl leading-tight sm:text-3xl'>
{featured.title}
</h2>
<p className='mb-4 text-gray-700 sm:text-base'>{featured.description}</p>
<div className='flex items-center gap-2'>
<div className='-space-x-2 flex'>
{(featured.authors && featured.authors.length > 0
? featured.authors
: [featured.author]
)
.slice(0, 3)
.map((author, idx) => (
<Avatar key={idx} className='size-5 border-2 border-white'>
<AvatarImage src={author?.avatarUrl} alt={author?.name} />
<AvatarFallback className='border-2 border-white bg-gray-100 text-gray-600 text-xs'>
{author?.name.slice(0, 2)}
</AvatarFallback>
</Avatar>
))}
</div>
<span className='text-gray-600 text-xs sm:text-sm'>
{(featured.authors && featured.authors.length > 0
? featured.authors
: [featured.author]
)
.slice(0, 2)
.map((a, i) => a?.name)
.join(', ')}
{(featured.authors && featured.authors.length > 0
? featured.authors
: [featured.author]
).length > 2 && (
<>
{' '}
and{' '}
{(featured.authors && featured.authors.length > 0
? featured.authors
: [featured.author]
).length - 2}{' '}
other
{(featured.authors && featured.authors.length > 0
? featured.authors
: [featured.author]
).length -
2 >
1
? 's'
: ''}
</>
)}
</span>
</div>
</div>
</div>
</Link>
)}
{/* Masonry-like list using CSS columns for varied heights */}
<div className='gap-6 [column-fill:_balance] md:columns-2 lg:columns-3'>
{rest.map((p, i) => {
const size = i % 3 === 0 ? 'h-64' : i % 3 === 1 ? 'h-56' : 'h-48'
return (
<Link
key={p.slug}
href={`/blog/${p.slug}`}
className='group mb-6 inline-block w-full break-inside-avoid'
>
<div className='overflow-hidden rounded-xl border border-gray-200 transition-colors duration-300 hover:border-gray-300'>
<Image
src={p.ogImage}
alt={p.title}
width={800}
height={450}
className={`${size} w-full object-cover`}
/>
<div className='p-4'>
<div className='mb-2 text-gray-600 text-xs'>
{new Date(p.date).toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})}
</div>
<h3 className='shine-text mb-1 font-medium text-lg leading-tight'>{p.title}</h3>
<p className='mb-3 line-clamp-3 text-gray-700 text-sm'>{p.description}</p>
<div className='flex items-center gap-2'>
<div className='-space-x-1.5 flex'>
{(p.authors && p.authors.length > 0 ? p.authors : [p.author])
.slice(0, 3)
.map((author, idx) => (
<Avatar key={idx} className='size-4 border border-white'>
<AvatarImage src={author?.avatarUrl} alt={author?.name} />
<AvatarFallback className='border border-white bg-gray-100 text-[10px] text-gray-600'>
{author?.name.slice(0, 2)}
</AvatarFallback>
</Avatar>
))}
</div>
<span className='text-gray-600 text-xs'>
{(p.authors && p.authors.length > 0 ? p.authors : [p.author])
.slice(0, 2)
.map((a) => a?.name)
.join(', ')}
{(p.authors && p.authors.length > 0 ? p.authors : [p.author]).length > 2 && (
<>
{' '}
and{' '}
{(p.authors && p.authors.length > 0 ? p.authors : [p.author]).length - 2}{' '}
other
{(p.authors && p.authors.length > 0 ? p.authors : [p.author]).length - 2 >
1
? 's'
: ''}
</>
)}
</span>
</div>
</div>
</div>
</Link>
)
})}
</div>
{totalPages > 1 && (
<div className='mt-10 flex items-center justify-center gap-3'>
{pageNum > 1 && (
<Link
href={`/blog?page=${pageNum - 1}${tag ? `&tag=${encodeURIComponent(tag)}` : ''}`}
className='rounded border px-3 py-1 text-sm'
>
Previous
</Link>
)}
<span className='text-gray-600 text-sm'>
Page {pageNum} of {totalPages}
</span>
{pageNum < totalPages && (
<Link
href={`/blog?page=${pageNum + 1}${tag ? `&tag=${encodeURIComponent(tag)}` : ''}`}
className='rounded border px-3 py-1 text-sm'
>
Next
</Link>
)}
</div>
)}
</main>
)
}

View File

@@ -0,0 +1,41 @@
import { NextResponse } from 'next/server'
import { getAllPostMeta } from '@/lib/blog/registry'
export const revalidate = 3600
export async function GET() {
const posts = await getAllPostMeta()
const items = posts.slice(0, 50)
const site = 'https://sim.ai'
const xml = `<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Sim Blog</title>
<link>${site}</link>
<description>Announcements, insights, and guides for AI agent workflows.</description>
${items
.map(
(p) => `
<item>
<title><![CDATA[${p.title}]]></title>
<link>${p.canonical}</link>
<guid>${p.canonical}</guid>
<pubDate>${new Date(p.date).toUTCString()}</pubDate>
<description><![CDATA[${p.description}]]></description>
${(p.authors || [p.author])
.map((a) => `<author><![CDATA[${a.name}${a.url ? ` (${a.url})` : ''}]]></author>`)
.join('\n')}
</item>`
)
.join('')}
</channel>
</rss>`
return new NextResponse(xml, {
headers: {
'Content-Type': 'application/xml; charset=utf-8',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=86400',
},
})
}

View File

@@ -0,0 +1,30 @@
import { NextResponse } from 'next/server'
import { getAllPostMeta } from '@/lib/blog/registry'
export const revalidate = 3600
export async function GET() {
const posts = await getAllPostMeta()
const base = 'https://sim.ai'
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
${posts
.map(
(p) => `<url>
<loc>${p.canonical}</loc>
<image:image>
<image:loc>${p.ogImage.startsWith('http') ? p.ogImage : `${base}${p.ogImage}`}</image:loc>
<image:title><![CDATA[${p.title}]]></image:title>
<image:caption><![CDATA[${p.description}]]></image:caption>
</image:image>
</url>`
)
.join('\n')}
</urlset>`
return new NextResponse(xml, {
headers: {
'Content-Type': 'application/xml; charset=utf-8',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=86400',
},
})
}

View File

@@ -0,0 +1,25 @@
import Link from 'next/link'
import { getAllTags } from '@/lib/blog/registry'
export default async function TagsIndex() {
const tags = await getAllTags()
return (
<main className='mx-auto max-w-[900px] px-6 py-10 sm:px-8 md:px-12'>
<h1 className='mb-6 font-medium text-[32px] leading-tight'>Browse by tag</h1>
<div className='flex flex-wrap gap-3'>
<Link href='/blog' className='rounded-full border border-gray-300 px-3 py-1 text-sm'>
All
</Link>
{tags.map((t) => (
<Link
key={t.tag}
href={`/blog?tag=${encodeURIComponent(t.tag)}`}
className='rounded-full border border-gray-300 px-3 py-1 text-sm'
>
{t.tag} ({t.count})
</Link>
))}
</div>
</main>
)
}

View File

@@ -20,7 +20,7 @@ interface NavProps {
}
export default function Nav({ hideAuthButtons = false, variant = 'landing' }: NavProps = {}) {
const [githubStars, setGithubStars] = useState('17.4k')
const [githubStars, setGithubStars] = useState('17.7k')
const [isHovered, setIsHovered] = useState(false)
const [isLoginHovered, setIsLoginHovered] = useState(false)
const router = useRouter()

View File

@@ -1,9 +1,9 @@
import type { MetadataRoute } from 'next'
import { getAllPostMeta } from '@/lib/blog/registry'
export default function sitemap(): MetadataRoute.Sitemap {
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = 'https://sim.ai'
// Static pages
const staticPages = [
{
url: baseUrl,
@@ -37,15 +37,13 @@ export default function sitemap(): MetadataRoute.Sitemap {
},
]
// Blog posts and content pages
const blogPages = [
{
url: `${baseUrl}/blog/openai-vs-n8n-vs-sim`,
lastModified: new Date('2025-10-11'),
changeFrequency: 'monthly' as const,
priority: 0.9,
},
]
const posts = await getAllPostMeta()
const blogPages = posts.map((p) => ({
url: p.canonical,
lastModified: new Date(p.updated ?? p.date),
changeFrequency: 'monthly' as const,
priority: 0.9 as const,
}))
return [...staticPages, ...blogPages]
}

View File

@@ -0,0 +1,7 @@
{
"id": "emir",
"name": "Emir Karabeg",
"url": "https://x.com/karabegemir",
"xHandle": "karabegemir",
"avatarUrl": "/blog/authors/emir.png"
}

View File

@@ -0,0 +1,7 @@
{
"id": "sim",
"name": "The Sim Team",
"url": "https://x.com/simdotai",
"xHandle": "simdotai",
"avatarUrl": "/logo/primary/small.png"
}

View File

@@ -0,0 +1,7 @@
{
"id": "waleed",
"name": "Waleed Latif",
"url": "https://x.com/typingwala",
"xHandle": "typingwala",
"avatarUrl": "/blog/authors/waleed.png"
}

View File

@@ -0,0 +1,216 @@
---
slug: openai-vs-n8n-vs-sim
title: 'OpenAI AgentKit vs n8n vs Sim: AI Agent Workflow Builder Comparison'
description: OpenAI just released AgentKit for building AI agents. How does it compare to workflow automation platforms like n8n and purpose-built AI agent builders like Sim?
date: 2025-10-06
updated: 2025-10-06
authors:
- emir
readingTime: 9
tags: [AI Agents, Workflow Automation, OpenAI AgentKit, n8n, Sim, MCP]
ogImage: /blog/openai-vs-n8n-vs-sim/workflow.png
canonical: https://sim.ai/blog/openai-vs-n8n-vs-sim
draft: false
---
When building AI agent workflows, developers often evaluate multiple platforms to find the right fit for their needs. Three platforms frequently come up in these discussions: OpenAI's new AgentKit, the established workflow automation tool n8n, and Sim, a purpose-built AI agent workflow builder. While all three enable AI agent development, they take fundamentally different approaches, each with distinct strengths and ideal use cases.
## What is OpenAI AgentKit?
OpenAI AgentKit is a set of building blocks designed to help developers take AI agents from prototype to production. Built on top of the OpenAI Responses API, it provides a structured approach to building and deploying intelligent agents.
![OpenAI AgentKit workflow interface](/blog/openai-vs-n8n-vs-sim/openai.png)
### Core Features
#### Agent Builder Canvas
AgentKit provides a visual canvas where developers can design and build agents. This interface allows you to model complex workflows visually, making it easier to understand and iterate on agent behavior. The builder is powered by OpenAI's Responses API.
#### ChatKit for Embedded Interfaces
ChatKit enables developers to embed chat interfaces to run workflows directly within their applications. It includes custom widgets that you can create and integrate, with the ability to preview interfaces right in the workflow builder before deployment.
![OpenAI AgentKit custom widgets interface](/blog/openai-vs-n8n-vs-sim/widgets.png)
#### Comprehensive Evaluation System
AgentKit includes out-of-the-box evaluation capabilities to measure agent performance. Features include datasets to assess agent nodes, prompt optimization tools, and the ability to run evaluations on external models beyond OpenAI's ecosystem.
#### Connectors and Integrations
The platform provides connectors to integrate with both internal tools and external services, enabling agents to interact with your existing tech stack.
#### API Publishing
Once your agent is ready, the publish feature allows you to integrate it as an API inside your codebase, making deployment straightforward.
#### Built-in Guardrails
AgentKit comes with guardrails out of the box, helping ensure agent behavior stays within defined boundaries and safety parameters.
### What AgentKit Doesn't Offer
While AgentKit is powerful for building agents, it has some limitations:
- Only able to run OpenAI models—no support for other AI providers
- Cannot make generic API requests in workflows—limited to MCP (Model Context Protocol) integrations only
- Not an open-source platform
- No workflow templates to accelerate development
- No execution logs or detailed monitoring for debugging and observability
- No ability to trigger workflows via external integrations
- Limited out-of-the-box integration options compared to dedicated workflow automation platforms
## What is n8n?
n8n is a workflow automation platform that excels at connecting various services and APIs together. While it started as a general automation tool, n8n has evolved to support AI agent workflows alongside its traditional integration capabilities.
![n8n workflow automation interface](/blog/openai-vs-n8n-vs-sim/n8n.png)
### Core Capabilities
#### Extensive Integration Library
n8n's primary strength lies in its vast library of pre-built integrations. With hundreds of connectors for popular services, it makes it easy to connect disparate systems without writing custom code.
#### Visual Workflow Builder
The platform provides a node-based visual interface for building workflows. Users can drag and drop nodes representing different services and configure how data flows between them.
#### Flexible Triggering Options
n8n supports various ways to trigger workflows, including webhooks, scheduled executions, and manual triggers, making it versatile for different automation scenarios.
#### AI and LLM Integration
More recently, n8n has added support for AI models and agent-like capabilities, allowing users to incorporate language models into their automation workflows.
#### Self-Hosting Options
n8n offers both cloud-hosted and self-hosted deployment options, giving organizations control over their data and infrastructure.
### Primary Use Cases
n8n is best suited for:
- Traditional workflow automation and service integration
- Data synchronization between business tools
- Event-driven automation workflows
- Simple AI-enhanced automations
### What n8n Doesn't Offer
While n8n is excellent for traditional automation, it has some limitations for AI agent development:
- No SDK to build workflows programmatically—limited to visual builder only
- Not fully open source but fair-use licensed, with some restrictions
- Free trial limited to 14 days, after which paid plans are required
- Limited/complex parallel execution handling
## What is Sim?
Sim is a fully open-source platform (Apache 2.0 license) specifically designed for AI agent development. Unlike platforms that added AI capabilities as an afterthought, Sim was created from the ground up to address the unique challenges of building, testing, and deploying production-ready AI agents.
### Comprehensive AI Agent Platform
#### Visual AI Workflow Builder
Sim provides an intuitive drag-and-drop canvas where developers can build complex AI agent workflows visually. The platform supports sophisticated agent architectures, including multi-agent systems, conditional logic, loops, and parallel execution paths. Additionally, Sim's built-in AI Copilot can assist you directly in the editor, helping you build and modify workflows faster with intelligent suggestions and explanations.
![Sim visual workflow builder with AI agent blocks](/blog/openai-vs-n8n-vs-sim/sim.png)
#### AI Copilot for Workflow Building
Sim includes an intelligent in-editor AI assistant that helps you build and edit workflows faster. Copilot can explain complex concepts, suggest best practices, and even make changes to your workflow when you approve them. Using the @ context menu, you can reference workflows, blocks, knowledge bases, documentation, templates, and execution logs—giving Copilot the full context it needs to provide accurate, relevant assistance. This dramatically accelerates workflow development compared to building from scratch.
![Sim AI Copilot assisting with workflow development](/blog/openai-vs-n8n-vs-sim/copilot.png)
#### Pre-Built Workflow Templates
Get started quickly with Sim's extensive library of pre-built workflow templates. Browse templates across categories like Marketing, Sales, Finance, Support, and Artificial Intelligence. Each template is a production-ready workflow you can customize for your needs, saving hours of development time. Templates are created by the Sim team and community members, with popularity ratings and integration counts to help you find the right starting point.
![Sim workflow templates gallery](/blog/openai-vs-n8n-vs-sim/templates.png)
#### 80+ Built-in Integrations
Out of the box, Sim connects with 80+ services including multiple AI providers (OpenAI, Anthropic, Google, Groq, Cerebras, local Ollama models), communication tools (Gmail, Slack, Teams, Telegram, WhatsApp), productivity apps (Notion, Google Sheets, Airtable, Monday.com), and developer tools (GitHub, GitLab).
#### Multiple Trigger Options
Unlike AgentKit, Sim workflows can be triggered in multiple ways: chat interfaces, REST APIs, webhooks, scheduled jobs, or external events from integrated services like Slack and GitHub. This flexibility ensures your agents can be activated however your use case demands.
#### Real-Time Team Collaboration
Sim enables multiple team members to work simultaneously on the same workflow with real-time editing, commenting, and comprehensive permissions management. This makes it ideal for teams building complex agent systems together.
#### Advanced Agent Capabilities
The platform includes specialized blocks for AI agents, RAG (Retrieval-Augmented Generation) systems, function calling, code execution, data processing, and evaluation. These purpose-built components enable developers to create sophisticated agentic workflows without custom coding.
#### Intelligent Knowledge Base with Vector Search
Sim's native knowledge base goes far beyond simple document storage. Powered by pgvector, it provides semantic search that understands meaning and context, not just keywords. Upload documents in multiple formats (PDF, Word, Excel, Markdown, and more), and Sim automatically processes them with intelligent chunking, generates vector embeddings, and makes them instantly searchable. The knowledge base supports natural language queries, concept-based retrieval, multi-language understanding, and configurable chunk sizes (100-4,000 characters). This makes building RAG agents straightforward—your AI can search through your organization's knowledge with context-aware precision.
#### Comprehensive Execution Logging and Monitoring
Sim provides enterprise-grade logging that captures every detail of workflow execution. Track workflow runs with execution IDs, view block-level logs with precise timing and duration metrics, monitor token usage and costs per execution, and debug failures with detailed error traces and trace spans. The logging system integrates with Copilot—you can reference execution logs directly in your Copilot conversations to understand what happened and troubleshoot issues. This level of observability is essential for production AI agents where understanding behavior and debugging issues quickly is critical.
![Sim execution logs and monitoring dashboard](/blog/openai-vs-n8n-vs-sim/logs.png)
#### Custom Integrations via MCP Protocol
Beyond the 80+ built-in integrations, Sim supports the Model Context Protocol (MCP), allowing developers to create custom integrations for proprietary systems or specialized tools.
#### Flexible Deployment Options
Sim offers both cloud-hosted and self-hosted deployment options. Organizations can run Sim on their own infrastructure for complete control, or use the managed cloud service for simplicity. The platform is SOC2 and HIPAA compliant, ensuring enterprise-level security.
#### Production-Ready Infrastructure
The platform includes everything needed for production deployments: background job processing, webhook handling, monitoring, and API management. Workflows can be published as REST API endpoints, embedded via SDKs, or run through chat interfaces.
### What You Can Build with Sim
- **AI Assistants & Chatbots:** Intelligent agents that search the web, access calendars, send emails, and interact with business tools
- **Business Process Automation:** Automate repetitive tasks like data entry, report generation, customer support, and content creation
- **Data Processing & Analysis:** Extract insights from documents, analyze datasets, generate reports, and sync data between systems
- **API Integration Workflows:** Connect multiple services into unified endpoints and orchestrate complex business logic
- **RAG Systems:** Build sophisticated retrieval-augmented generation pipelines with custom knowledge bases
### Drawbacks to Consider
While Sim excels at AI agent workflows, there are some tradeoffs:
- Fewer pre-built integrations compared to n8n's extensive library—though Sim's 80+ integrations cover most AI agent use cases and MCP protocol enables custom integrations
## Key Differences
While all three platforms enable AI agent development, they excel in different areas:
### OpenAI AgentKit
**Best for:** Teams deeply invested in the OpenAI ecosystem who prioritize evaluation and testing capabilities. Ideal when you need tight integration with OpenAI's latest models and want built-in prompt optimization and evaluation tools.
**Limitations:** Locked into OpenAI models only, not open-source, no workflow templates or execution logs, limited triggering options, and fewer out-of-the-box integrations.
### n8n
**Best for:** Traditional workflow automation with some AI enhancement. Excellent when your primary need is connecting business tools and services, with AI as a complementary feature rather than the core focus.
**Limitations:** No SDK for programmatic workflow building, fair-use licensing (not fully open source), 14-day trial limitation, and AI agent capabilities are newer and less mature compared to its traditional automation features.
### Sim
**Best for:** Building production-ready AI agent workflows that require flexibility, collaboration, and comprehensive tooling. Ideal for teams that need AI Copilot assistance, advanced knowledge base features, detailed logging, and the ability to work across multiple AI providers with purpose-built agentic workflow tools.
**Limitations:** Fewer integrations than n8n's extensive library, though the 80+ built-in integrations and MCP protocol support cover most AI agent needs.
## Which Should You Choose?
The right platform depends on your specific needs and context:
Choose **OpenAI AgentKit** if you're exclusively using OpenAI models and want to build chat interfaces with the ChatKit. It's a solid choice for teams that want to stay within OpenAI's ecosystem and prioritize testing capabilities.
Choose **n8n** if your primary use case is traditional workflow automation between business tools, with occasional AI enhancement. It's ideal for organizations already familiar with n8n who want to add some AI capabilities to existing automations.
Choose **Sim** if you're building AI agents as your primary objective and need a platform purpose-built for that use case. Sim provides the most comprehensive feature set for agentic workflows, with AI Copilot to accelerate development, parallel execution handling, intelligent knowledge base for RAG applications, detailed execution logging for production monitoring, flexibility across AI providers, extensive integrations, team collaboration, and deployment options that scale from prototype to production.

16
apps/sim/lib/blog/faq.tsx Normal file
View File

@@ -0,0 +1,16 @@
export function FAQ({ items }: { items: { q: string; a: string }[] }) {
if (!items || items.length === 0) return null
return (
<section className='mt-12'>
<h2 className='mb-4 font-medium text-[24px]'>FAQ</h2>
<div className='space-y-6'>
{items.map((it, i) => (
<div key={i}>
<h3 className='mb-2 font-medium text-[20px]'>{it.q}</h3>
<p className='text-[19px] text-gray-800 leading-relaxed'>{it.a}</p>
</div>
))}
</div>
</section>
)
}

65
apps/sim/lib/blog/mdx.tsx Normal file
View File

@@ -0,0 +1,65 @@
import clsx from 'clsx'
import Image from 'next/image'
import type { MDXRemoteProps } from 'next-mdx-remote/rsc'
export const mdxComponents: MDXRemoteProps['components'] = {
img: (props: any) => (
<Image
src={props.src}
alt={props.alt || ''}
width={props.width ? Number(props.width) : 800}
height={props.height ? Number(props.height) : 450}
className={clsx('w-full rounded-lg', props.className)}
/>
),
h2: (props: any) => (
<h2
{...props}
style={{ fontSize: '30px', marginTop: '3rem', marginBottom: '1.5rem' }}
className={clsx('font-medium text-black leading-tight', props.className)}
/>
),
h3: (props: any) => (
<h3
{...props}
style={{ fontSize: '24px', marginTop: '1.5rem', marginBottom: '0.75rem' }}
className={clsx('font-medium leading-tight', props.className)}
/>
),
h4: (props: any) => (
<h4
{...props}
style={{ fontSize: '19px', marginTop: '1.5rem', marginBottom: '0.75rem' }}
className={clsx('font-medium leading-tight', props.className)}
/>
),
p: (props: any) => (
<p
{...props}
style={{ fontSize: '19px', marginBottom: '1.5rem', fontWeight: '400' }}
className={clsx('text-gray-800 leading-relaxed', props.className)}
/>
),
ul: (props: any) => (
<ul
{...props}
style={{ fontSize: '19px', marginBottom: '1rem', fontWeight: '400' }}
className={clsx('list-outside list-disc pl-6 text-gray-800 leading-relaxed', props.className)}
/>
),
ol: (props: any) => (
<ol
{...props}
style={{ fontSize: '19px', marginBottom: '1rem', fontWeight: '400' }}
className={clsx(
'list-outside list-decimal pl-6 text-gray-800 leading-relaxed',
props.className
)}
/>
),
li: (props: any) => <li {...props} className={clsx('mb-2', props.className)} />,
strong: (props: any) => <strong {...props} className={clsx('font-semibold', props.className)} />,
figure: (props: any) => (
<figure {...props} className={clsx('my-8 overflow-hidden rounded-lg', props.className)} />
),
}

View File

@@ -0,0 +1,158 @@
import fs from 'fs/promises'
import path from 'path'
import matter from 'gray-matter'
import { compileMDX } from 'next-mdx-remote/rsc'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import rehypeSlug from 'rehype-slug'
import remarkGfm from 'remark-gfm'
import { mdxComponents } from './mdx'
import type { BlogMeta, BlogPost, TagWithCount } from './schema'
import { AuthorSchema, BlogFrontmatterSchema } from './schema'
import { AUTHORS_DIR, BLOG_DIR, byDateDesc, ensureContentDirs, toIsoDate } from './utils'
let cachedMeta: BlogMeta[] | null = null
let cachedAuthors: Record<string, any> | null = null
async function loadAuthors(): Promise<Record<string, any>> {
if (cachedAuthors) return cachedAuthors
await ensureContentDirs()
const files = await fs.readdir(AUTHORS_DIR).catch(() => [])
const authors: Record<string, any> = {}
for (const file of files) {
if (!file.endsWith('.json')) continue
const raw = await fs.readFile(path.join(AUTHORS_DIR, file), 'utf-8')
const json = JSON.parse(raw)
const author = AuthorSchema.parse(json)
authors[author.id] = author
}
cachedAuthors = authors
return authors
}
function slugify(text: string): string {
return text
.toLowerCase()
.trim()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '-')
}
async function scanFrontmatters(): Promise<BlogMeta[]> {
if (cachedMeta) return cachedMeta
await ensureContentDirs()
const entries = await fs.readdir(BLOG_DIR).catch(() => [])
const authorsMap = await loadAuthors()
const results: BlogMeta[] = []
for (const slug of entries) {
const postDir = path.join(BLOG_DIR, slug)
const stat = await fs.stat(postDir).catch(() => null)
if (!stat || !stat.isDirectory()) continue
const mdxPath = path.join(postDir, 'index.mdx')
const hasMdx = await fs
.stat(mdxPath)
.then((s) => s.isFile())
.catch(() => false)
if (!hasMdx) continue
const raw = await fs.readFile(mdxPath, 'utf-8')
const { data } = matter(raw)
const fm = BlogFrontmatterSchema.parse(data)
const authors = fm.authors.map((id) => authorsMap[id]).filter(Boolean)
if (authors.length === 0) throw new Error(`Authors not found for "${slug}"`)
results.push({
slug: fm.slug,
title: fm.title,
description: fm.description,
date: toIsoDate(fm.date),
updated: fm.updated ? toIsoDate(fm.updated) : undefined,
author: authors[0],
authors,
readingTime: fm.readingTime,
tags: fm.tags,
ogImage: fm.ogImage,
canonical: fm.canonical,
ogAlt: fm.ogAlt,
about: fm.about,
timeRequired: fm.timeRequired,
faq: fm.faq,
draft: fm.draft,
})
}
cachedMeta = results.sort(byDateDesc)
return cachedMeta
}
export async function getAllPostMeta(): Promise<BlogMeta[]> {
return (await scanFrontmatters()).filter((p) => !p.draft)
}
export async function getAllTags(): Promise<TagWithCount[]> {
const posts = await getAllPostMeta()
const counts: Record<string, number> = {}
for (const p of posts) {
for (const t of p.tags) counts[t] = (counts[t] || 0) + 1
}
return Object.entries(counts)
.map(([tag, count]) => ({ tag, count }))
.sort((a, b) => b.count - a.count || a.tag.localeCompare(b.tag))
}
export async function getPostBySlug(slug: string): Promise<BlogPost> {
const meta = await scanFrontmatters()
const found = meta.find((m) => m.slug === slug)
if (!found) throw new Error(`Post not found: ${slug}`)
const mdxPath = path.join(BLOG_DIR, slug, 'index.mdx')
const raw = await fs.readFile(mdxPath, 'utf-8')
const { content, data } = matter(raw)
const fm = BlogFrontmatterSchema.parse(data)
const compiled = await compileMDX({
source: content,
components: mdxComponents as any,
options: {
parseFrontmatter: false,
mdxOptions: {
remarkPlugins: [remarkGfm],
rehypePlugins: [
rehypeSlug,
[rehypeAutolinkHeadings, { behavior: 'wrap', properties: { className: 'anchor' } }],
],
},
},
})
const headings: { text: string; id: string }[] = []
const lines = content.split('\n')
for (const line of lines) {
const match = /^##\s+(.+)$/.exec(line.trim())
if (match) {
const text = match[1].trim()
headings.push({ text, id: slugify(text) })
}
}
return {
...found,
Content: () => (compiled as any).content,
updated: fm.updated ? toIsoDate(fm.updated) : found.updated,
headings,
}
}
export function invalidateBlogCaches() {
cachedMeta = null
cachedAuthors = null
}
export async function getRelatedPosts(slug: string, limit = 3): Promise<BlogMeta[]> {
const posts = await getAllPostMeta()
const current = posts.find((p) => p.slug === slug)
if (!current) return []
const scored = posts
.filter((p) => p.slug !== slug)
.map((p) => ({
post: p,
score: p.tags.filter((t) => current.tags.includes(t)).length,
}))
.filter((x) => x.score > 0)
.sort((a, b) => b.score - a.score || byDateDesc(a.post, b.post))
.slice(0, limit)
.map((x) => x.post)
return scored
}

View File

@@ -0,0 +1,72 @@
import { z } from 'zod'
export const AuthorSchema = z
.object({
id: z.string().min(1),
name: z.string().min(1),
url: z.string().url().optional(),
xHandle: z.string().optional(),
avatarUrl: z.string().optional(), // allow relative or absolute
})
.strict()
export type Author = z.infer<typeof AuthorSchema>
export const BlogFrontmatterSchema = z
.object({
slug: z.string().min(1),
title: z.string().min(5),
description: z.string().min(20),
date: z.coerce.date(),
updated: z.coerce.date().optional(),
authors: z.array(z.string()).min(1),
readingTime: z.number().int().positive().optional(),
tags: z.array(z.string()).default([]),
ogImage: z.string().min(1),
ogAlt: z.string().optional(),
about: z.array(z.string()).optional(),
timeRequired: z.string().optional(),
faq: z
.array(
z.object({
q: z.string().min(1),
a: z.string().min(1),
})
)
.optional(),
canonical: z.string().url(),
draft: z.boolean().default(false),
})
.strict()
export type BlogFrontmatter = z.infer<typeof BlogFrontmatterSchema>
export interface BlogMeta {
slug: string
title: string
description: string
date: string // ISO
updated?: string // ISO
author: Author
authors: Author[]
readingTime?: number
tags: string[]
ogImage: string
ogAlt?: string
about?: string[]
timeRequired?: string
faq?: { q: string; a: string }[]
canonical: string
draft: boolean
sourcePath?: string
}
export interface BlogPost extends BlogMeta {
Content: React.ComponentType
headings?: { text: string; id: string }[]
}
export interface TagWithCount {
tag: string
count: number
}

134
apps/sim/lib/blog/seo.ts Normal file
View File

@@ -0,0 +1,134 @@
import type { Metadata } from 'next'
import type { BlogMeta } from './schema'
export function buildPostMetadata(post: BlogMeta): Metadata {
const base = new URL(post.canonical)
const baseUrl = `${base.protocol}//${base.host}`
return {
title: post.title,
description: post.description,
keywords: post.tags,
authors: (post.authors && post.authors.length > 0 ? post.authors : [post.author]).map((a) => ({
name: a.name,
url: a.url,
})),
creator: post.author.name,
publisher: 'Sim',
robots: post.draft
? { index: false, follow: false, googleBot: { index: false, follow: false } }
: { index: true, follow: true, googleBot: { index: true, follow: true } },
alternates: { canonical: post.canonical },
openGraph: {
title: post.title,
description: post.description,
url: post.canonical,
siteName: 'Sim',
locale: 'en_US',
type: 'article',
publishedTime: post.date,
modifiedTime: post.updated ?? post.date,
authors: (post.authors && post.authors.length > 0 ? post.authors : [post.author]).map(
(a) => a.name
),
tags: post.tags,
images: [
{
url: post.ogImage.startsWith('http') ? post.ogImage : `${baseUrl}${post.ogImage}`,
width: 1200,
height: 630,
alt: post.ogAlt || post.title,
},
],
},
twitter: {
card: 'summary_large_image',
title: post.title,
description: post.description,
images: [post.ogImage],
creator: post.author.url?.includes('x.com') ? `@${post.author.xHandle || ''}` : undefined,
site: '@simdotai',
},
other: {
'article:published_time': post.date,
'article:modified_time': post.updated ?? post.date,
'article:author': post.author.name,
'article:section': 'Technology',
},
}
}
export function buildArticleJsonLd(post: BlogMeta) {
return {
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: post.title,
description: post.description,
image: [
{
'@type': 'ImageObject',
url: post.ogImage,
caption: post.ogAlt || post.title,
},
],
datePublished: post.date,
dateModified: post.updated ?? post.date,
author: (post.authors && post.authors.length > 0 ? post.authors : [post.author]).map((a) => ({
'@type': 'Person',
name: a.name,
url: a.url,
})),
publisher: {
'@type': 'Organization',
name: 'Sim',
logo: {
'@type': 'ImageObject',
url: 'https://sim.ai/logo/primary/medium.png',
},
},
mainEntityOfPage: {
'@type': 'WebPage',
'@id': post.canonical,
},
keywords: post.tags.join(', '),
about: (post.about || []).map((a) => ({ '@type': 'Thing', name: a })),
isAccessibleForFree: true,
timeRequired: post.timeRequired,
articleSection: 'Technology',
inLanguage: 'en-US',
}
}
export function buildBreadcrumbJsonLd(post: BlogMeta) {
return {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{ '@type': 'ListItem', position: 1, name: 'Home', item: 'https://sim.ai' },
{ '@type': 'ListItem', position: 2, name: 'Blog', item: 'https://sim.ai/blog' },
{ '@type': 'ListItem', position: 3, name: post.title, item: post.canonical },
],
}
}
export function buildFaqJsonLd(items: { q: string; a: string }[] | undefined) {
if (!items || items.length === 0) return null
return {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: items.map((it) => ({
'@type': 'Question',
name: it.q,
acceptedAnswer: { '@type': 'Answer', text: it.a },
})),
}
}
export function buildBlogJsonLd() {
return {
'@context': 'https://schema.org',
'@type': 'Blog',
name: 'Sim Blog',
url: 'https://sim.ai/blog',
description: 'Announcements, insights, and guides for building AI agent workflows.',
}
}

View File

@@ -0,0 +1,27 @@
import fs from 'fs/promises'
import path from 'path'
export const BLOG_DIR = path.join(process.cwd(), 'content', 'blog')
export const AUTHORS_DIR = path.join(process.cwd(), 'content', 'authors')
export async function ensureContentDirs() {
await fs.mkdir(BLOG_DIR, { recursive: true })
await fs.mkdir(AUTHORS_DIR, { recursive: true })
}
export function toIsoDate(value: Date | string | number): string {
if (value instanceof Date) return value.toISOString()
return new Date(value).toISOString()
}
export function byDateDesc<T extends { date: string }>(a: T, b: T) {
return new Date(b.date).getTime() - new Date(a.date).getTime()
}
export function stripMdxExtension(file: string) {
return file.replace(/\.mdx?$/i, '')
}
export function isRelativeUrl(url: string) {
return url.startsWith('/')
}

View File

@@ -216,6 +216,20 @@ const nextConfig: NextConfig = {
permanent: true,
})
// Move root feeds to blog namespace
redirects.push(
{
source: '/rss.xml',
destination: '/blog/rss.xml',
permanent: true,
},
{
source: '/sitemap-images.xml',
destination: '/blog/sitemap-images.xml',
permanent: true,
}
)
// Only enable domain redirects for the hosted version
if (isHosted) {
redirects.push(

View File

@@ -90,12 +90,14 @@
"mammoth": "^1.9.0",
"mysql2": "3.14.3",
"next": "^15.4.1",
"next-mdx-remote": "^5.0.0",
"next-runtime-env": "3.3.0",
"next-themes": "^0.4.6",
"officeparser": "^5.2.0",
"openai": "^4.91.1",
"papaparse": "5.5.3",
"pdf-parse": "2.4.5",
"gray-matter": "^4.0.3",
"posthog-js": "1.268.9",
"posthog-node": "5.9.2",
"prismjs": "^1.30.0",
@@ -108,6 +110,8 @@
"react-simple-code-editor": "^0.14.1",
"reactflow": "^11.11.4",
"remark-gfm": "4.0.1",
"rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0",
"resend": "^4.1.2",
"sharp": "0.34.3",
"socket.io": "^4.8.1",

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@@ -113,6 +113,7 @@
"framer-motion": "^12.5.0",
"fuse.js": "7.1.0",
"geist": "1.4.2",
"gray-matter": "^4.0.3",
"groq-sdk": "^0.15.0",
"html-to-text": "^9.0.5",
"input-otp": "^1.4.2",
@@ -126,6 +127,7 @@
"mammoth": "^1.9.0",
"mysql2": "3.14.3",
"next": "^15.4.1",
"next-mdx-remote": "^5.0.0",
"next-runtime-env": "3.3.0",
"next-themes": "^0.4.6",
"officeparser": "^5.2.0",
@@ -143,6 +145,8 @@
"react-markdown": "^10.1.0",
"react-simple-code-editor": "^0.14.1",
"reactflow": "^11.11.4",
"rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0",
"remark-gfm": "4.0.1",
"resend": "^4.1.2",
"sharp": "0.34.3",
@@ -656,6 +660,8 @@
"@mdx-js/mdx": ["@mdx-js/mdx@3.1.1", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="],
"@mdx-js/react": ["@mdx-js/react@3.1.1", "", { "dependencies": { "@types/mdx": "^2.0.0" }, "peerDependencies": { "@types/react": ">=16", "react": ">=16" } }, "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw=="],
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.20.2", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-6rqTdFt67AAAzln3NOKsXRmv5ZzPkgbfaebKBqUbts7vK1GZudqnrun5a8d3M/h955cam9RHZ6Jb4Y1XhnmFPg=="],
"@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.3.1", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-6nZrq5kfAz0POWyhljnbWQQJQ5uT8oE2ddX303q1uY0tWsivWKgBDXBBvuFPwOqRRalXJuVO9EjOdVtuhLX0zg=="],
@@ -1830,6 +1836,8 @@
"escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
"esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="],
"estree-util-attach-comments": ["estree-util-attach-comments@3.0.0", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw=="],
"estree-util-build-jsx": ["estree-util-build-jsx@3.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-walker": "^3.0.0" } }, "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ=="],
@@ -1872,6 +1880,8 @@
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
"extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="],
"fast-content-type-parse": ["fast-content-type-parse@2.0.1", "", {}, "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q=="],
"fast-copy": ["fast-copy@3.0.2", "", {}, "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ=="],
@@ -1980,6 +1990,8 @@
"graphql": ["graphql@15.10.1", "", {}, "sha512-BL/Xd/T9baO6NFzoMpiMD7YUZ62R6viR5tp/MULVEnbYJXZA//kRNW7J0j1w/wXArgL0sCxhDfK5dczSKn3+cg=="],
"gray-matter": ["gray-matter@4.0.3", "", { "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" } }, "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q=="],
"groq-sdk": ["groq-sdk@0.15.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-aYDEdr4qczx3cLCRRe+Beb37I7g/9bD5kHF+EEDxcrREWw1vKoRcfP3vHEkJB7Ud/8oOuF0scRwDpwWostTWuQ=="],
"gtoken": ["gtoken@7.1.0", "", { "dependencies": { "gaxios": "^6.0.0", "jws": "^4.0.0" } }, "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw=="],
@@ -1992,6 +2004,10 @@
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
"hast-util-heading-rank": ["hast-util-heading-rank@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA=="],
"hast-util-is-element": ["hast-util-is-element@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g=="],
"hast-util-to-estree": ["hast-util-to-estree@3.1.3", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-attach-comments": "^3.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w=="],
"hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="],
@@ -2070,6 +2086,8 @@
"is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="],
"is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
@@ -2152,6 +2170,8 @@
"jwt-decode": ["jwt-decode@4.0.0", "", {}, "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA=="],
"kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="],
"kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
"kysely": ["kysely@0.28.7", "", {}, "sha512-u/cAuTL4DRIiO2/g4vNGRgklEKNIj5Q3CG7RoUB5DV5SfEC2hMvPxKi0GWPmnzwL2ryIeud2VTcEEmqzTzEPNw=="],
@@ -2424,6 +2444,8 @@
"next": ["next@15.4.1", "", { "dependencies": { "@next/env": "15.4.1", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.4.1", "@next/swc-darwin-x64": "15.4.1", "@next/swc-linux-arm64-gnu": "15.4.1", "@next/swc-linux-arm64-musl": "15.4.1", "@next/swc-linux-x64-gnu": "15.4.1", "@next/swc-linux-x64-musl": "15.4.1", "@next/swc-win32-arm64-msvc": "15.4.1", "@next/swc-win32-x64-msvc": "15.4.1", "sharp": "^0.34.3" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-eNKB1q8C7o9zXF8+jgJs2CzSLIU3T6bQtX6DcTnCq1sIR1CJ0GlSyRs1BubQi3/JgCnr9Vr+rS5mOMI38FFyQw=="],
"next-mdx-remote": ["next-mdx-remote@5.0.0", "", { "dependencies": { "@babel/code-frame": "^7.23.5", "@mdx-js/mdx": "^3.0.1", "@mdx-js/react": "^3.0.1", "unist-util-remove": "^3.1.0", "vfile": "^6.0.1", "vfile-matter": "^5.0.0" }, "peerDependencies": { "react": ">=16" } }, "sha512-RNNbqRpK9/dcIFZs/esQhuLA8jANqlH694yqoDBK8hkVdJUndzzGmnPHa2nyi90N4Z9VmzuSWNRpr5ItT3M7xQ=="],
"next-runtime-env": ["next-runtime-env@3.3.0", "", { "dependencies": { "next": "^14", "react": "^18" } }, "sha512-JgKVnog9mNbjbjH9csVpMnz2tB2cT5sLF+7O47i6Ze/s/GoiKdV7dHhJHk1gwXpo6h5qPj5PTzryldtSjvrHuQ=="],
"next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="],
@@ -2692,8 +2714,12 @@
"regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="],
"rehype-autolink-headings": ["rehype-autolink-headings@7.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@ungap/structured-clone": "^1.0.0", "hast-util-heading-rank": "^3.0.0", "hast-util-is-element": "^3.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw=="],
"rehype-recma": ["rehype-recma@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "hast-util-to-estree": "^3.0.0" } }, "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw=="],
"rehype-slug": ["rehype-slug@6.0.0", "", { "dependencies": { "@types/hast": "^3.0.0", "github-slugger": "^2.0.0", "hast-util-heading-rank": "^3.0.0", "hast-util-to-string": "^3.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A=="],
"remark": ["remark@15.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A=="],
"remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="],
@@ -2756,6 +2782,8 @@
"scroll-into-view-if-needed": ["scroll-into-view-if-needed@3.1.0", "", { "dependencies": { "compute-scroll-into-view": "^3.0.2" } }, "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ=="],
"section-matter": ["section-matter@1.0.0", "", { "dependencies": { "extend-shallow": "^2.0.1", "kind-of": "^6.0.0" } }, "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA=="],
"secure-json-parse": ["secure-json-parse@4.0.0", "", {}, "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA=="],
"selderee": ["selderee@0.11.0", "", { "dependencies": { "parseley": "^0.12.0" } }, "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA=="],
@@ -2872,6 +2900,8 @@
"strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="],
"strip-bom-string": ["strip-bom-string@1.0.0", "", {}, "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g=="],
"strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="],
"strip-indent": ["strip-indent@3.0.0", "", { "dependencies": { "min-indent": "^1.0.0" } }, "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ=="],
@@ -3026,6 +3056,8 @@
"unist-util-position-from-estree": ["unist-util-position-from-estree@2.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ=="],
"unist-util-remove": ["unist-util-remove@3.1.1", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0", "unist-util-visit-parents": "^5.0.0" } }, "sha512-kfCqZK5YVY5yEa89tvpl7KnBBHu2c6CzMkqHUrlOqaRgGOMp0sMvwWOVrbAtj03KhovQB7i96Gda72v/EFE0vw=="],
"unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
"unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="],
@@ -3058,6 +3090,8 @@
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
"vfile-matter": ["vfile-matter@5.0.1", "", { "dependencies": { "vfile": "^6.0.0", "yaml": "^2.0.0" } }, "sha512-o6roP82AiX0XfkyTHyRCMXgHfltUNlXSEqCIS80f+mbAyiQBE2fxtDVMtseyytGx75sihiJFo/zR6r/4LTs2Cw=="],
"vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
"vite": ["vite@7.1.7", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA=="],
@@ -3440,6 +3474,8 @@
"google-auth-library/jws": ["jws@4.0.0", "", { "dependencies": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" } }, "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg=="],
"gray-matter/js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="],
"groq-sdk/@types/node": ["@types/node@18.19.128", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-m7wxXGpPpqxp2QDi/rpih5O772APRuBIa/6XiGqLNoM1txkjI8Sz1V4oSXJxQLTz/yP5mgy9z6UXEO6/lP70Gg=="],
"groq-sdk/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
@@ -3594,6 +3630,12 @@
"unicode-trie/pako": ["pako@0.2.9", "", {}, "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="],
"unist-util-remove/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
"unist-util-remove/unist-util-is": ["unist-util-is@5.2.1", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw=="],
"unist-util-remove/unist-util-visit-parents": ["unist-util-visit-parents@5.1.3", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0" } }, "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg=="],
"vite-tsconfig-paths/tsconfck": ["tsconfck@3.1.6", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"], "bin": { "tsconfck": "bin/tsconfck.js" } }, "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w=="],
"vitest/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],
@@ -3732,6 +3774,8 @@
"google-auth-library/jws/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
"groq-sdk/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"groq-sdk/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],