-
Notifications
You must be signed in to change notification settings - Fork 967
feat(marketing): add blog system with MDX support #929
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
56bcff2
feat(marketing): add blog system with MDX support
AviPeltz 459ed7d
style(marketing): add Vercel-style grid crosses and borders to blog
AviPeltz ff0c59d
make style great
AviPeltz bd2a138
lint
AviPeltz 059ad1f
images
AviPeltz 3eebea9
avatars
AviPeltz 54ae5ac
author sections
AviPeltz dde6388
Merge remote-tracking branch 'origin/main' into mogging-and-blogging
AviPeltz dfee148
bloging fixes and merged in main
AviPeltz 392602c
lint typecheck
AviPeltz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| --- | ||
| title: The History of Git Worktrees | ||
| description: How git worktrees evolved from a niche feature to the foundation of modern parallel development workflows. | ||
| author: Avi Peltz | ||
| date: 2025-01-18 | ||
| category: Research | ||
| --- | ||
|
|
||
| Git worktrees have become an essential tool for developers managing multiple tasks simultaneously. But where did they come from, and why are they suddenly so relevant? | ||
|
|
||
|  | ||
|
|
||
| ## The Early Days | ||
|
|
||
| Git worktrees were introduced in Git 2.5 (July 2015) as a way to have multiple working directories attached to a single repository. Before worktrees, developers had two options for working on multiple branches simultaneously: | ||
|
|
||
| 1. **Stash and switch** - Constantly stashing changes and switching branches | ||
| 2. **Multiple clones** - Maintaining separate clones of the same repository | ||
|
|
||
| Both approaches had significant drawbacks. Stashing was error-prone and disruptive. Multiple clones wasted disk space and made it difficult to share local commits between workspaces. | ||
|
|
||
| ## How Worktrees Work | ||
|
|
||
| A git worktree creates a new working directory that shares the same `.git` directory as your main repository. This means: | ||
|
|
||
| - All branches and commits are instantly available | ||
| - No need to push/pull between directories | ||
| - Minimal disk space overhead | ||
| - Each worktree can have its own branch checked out | ||
|
|
||
| ```bash | ||
| # Create a new worktree | ||
| git worktree add ../feature-branch feature/new-feature | ||
|
|
||
| # List all worktrees | ||
| git worktree list | ||
|
|
||
| # Remove a worktree | ||
| git worktree remove ../feature-branch | ||
| ``` | ||
|
|
||
| ## The AI Agent Revolution | ||
|
|
||
| With the rise of AI coding agents, worktrees have found a new purpose. When you're running multiple agents in parallel, each one needs: | ||
|
|
||
| - Its own working directory | ||
| - Isolation from other agents' changes | ||
| - Access to the full repository history | ||
|
|
||
| Worktrees provide all of this out of the box. That's why Superset uses them as the foundation for parallel agent workspaces. | ||
|
|
||
| ## Best Practices | ||
|
|
||
| When using worktrees for parallel development: | ||
|
|
||
| - **Use descriptive paths** - Name your worktree directories after the feature or task | ||
| - **Clean up regularly** - Remove worktrees when you're done with them | ||
| - **Avoid long-lived worktrees** - Merge or rebase frequently to avoid drift | ||
|
|
||
| ## Conclusion | ||
|
|
||
| What started as a niche feature for advanced Git users has become essential infrastructure for the age of AI-assisted development. As coding agents become more capable, the ability to run them in parallel—powered by git worktrees—will only become more important. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| --- | ||
| title: Introducing Superset | ||
| description: Run 10+ parallel coding agents on your machine. A new way to work with AI coding assistants. | ||
| author: Avi Peltz | ||
| date: 2025-01-15 | ||
| category: Product | ||
| --- | ||
|
|
||
| We're excited to introduce Superset - a new way to work with AI coding agents. | ||
|
|
||
| ## The Problem | ||
|
|
||
| Modern AI coding assistants are powerful, but they have a fundamental limitation: you can only run one task at a time. When your agent is working on a complex feature, you're stuck waiting. Context switching between different projects means losing your train of thought. | ||
|
|
||
| ## The Solution | ||
|
|
||
| Superset lets you run **10+ parallel coding agents** on your machine. Here's what that means for your workflow: | ||
|
|
||
| - **Spin up new tasks** while waiting for your current agent to finish | ||
| - **Quickly switch between tasks** as they need your attention | ||
| - **Keep your context** across multiple projects and features | ||
|
|
||
| ## How It Works | ||
|
|
||
| Superset uses isolated workspaces powered by git worktrees. Each task runs in its own environment, with its own terminal, its own files, and its own agent context. | ||
|
|
||
|  | ||
|
|
||
| ```bash | ||
| # Create a new workspace for a feature | ||
| superset create --branch feature/auth | ||
|
|
||
| # Your agent works in isolation | ||
| # Meanwhile, start another task... | ||
| superset create --branch feature/dashboard | ||
| ``` | ||
|
|
||
| ## What's Next | ||
|
|
||
| We're just getting started. In the coming weeks, we'll be sharing more about: | ||
|
|
||
| - Deep integrations with popular AI coding tools | ||
| - Advanced workspace management features | ||
| - Team collaboration capabilities | ||
|
|
||
| Stay tuned for updates. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| --- | ||
| title: A Guide to Parallel Coding Agents | ||
| description: Learn how to maximize your productivity by running multiple AI coding agents simultaneously. | ||
| author: Avi Peltz | ||
| date: 2025-01-20 | ||
| category: Research | ||
| --- | ||
|
|
||
| Running multiple AI coding agents in parallel can dramatically boost your productivity. Here's how to make the most of it. | ||
|
|
||
| ## Why Parallel Agents? | ||
|
|
||
| Traditional AI coding workflows are sequential. You ask your agent to do something, wait for it to finish, review the results, and move on. But what if you could: | ||
|
|
||
| 1. Start a refactoring task | ||
| 2. While that's running, begin a new feature | ||
| 3. Review completed tasks as they finish | ||
| 4. Context switch without losing progress | ||
|
|
||
| ## Setting Up Your Workflow | ||
|
|
||
| ### Creating Workspaces | ||
|
|
||
| Each parallel agent runs in its own isolated workspace. Here's how to create one: | ||
|
|
||
| ```bash | ||
| # Create a new workspace for a feature | ||
| superset create --branch feature/auth | ||
|
|
||
| # List all active workspaces | ||
| superset list | ||
|
|
||
| # Switch to a workspace | ||
| superset switch feature/auth | ||
| ``` | ||
|
|
||
| <Video src="/blog/parallel-agents-guide/parallel-agents-demo.mov" title="Parallel agents in action" /> | ||
|
|
||
| ### Organize by Task Type | ||
|
|
||
| Group your parallel workspaces by task type: | ||
|
|
||
| - **Feature development** - New functionality | ||
| - **Bug fixes** - Quick patches | ||
| - **Refactoring** - Code improvements | ||
| - **Documentation** - README updates, comments | ||
|
|
||
| ### Example: React Component | ||
|
|
||
| Here's an example of a component you might build in parallel: | ||
|
|
||
| ```tsx | ||
| import { useState, useEffect } from 'react'; | ||
|
|
||
| interface User { | ||
| id: string; | ||
| name: string; | ||
| email: string; | ||
| } | ||
|
|
||
| export function UserProfile({ userId }: { userId: string }) { | ||
| const [user, setUser] = useState<User | null>(null); | ||
| const [loading, setLoading] = useState(true); | ||
|
|
||
| useEffect(() => { | ||
| async function fetchUser() { | ||
| const response = await fetch(`/api/users/${userId}`); | ||
| const data = await response.json(); | ||
| setUser(data); | ||
| setLoading(false); | ||
| } | ||
| fetchUser(); | ||
| }, [userId]); | ||
|
|
||
| if (loading) return <div>Loading...</div>; | ||
| if (!user) return <div>User not found</div>; | ||
|
|
||
| return ( | ||
| <div className="p-4 rounded-lg border"> | ||
| <h2 className="text-xl font-bold">{user.name}</h2> | ||
| <p className="text-gray-600">{user.email}</p> | ||
| </div> | ||
| ); | ||
| } | ||
| ``` | ||
|
|
||
| ### API Routes | ||
|
|
||
| While one agent works on the frontend, another can build the API: | ||
|
|
||
| ```typescript | ||
| import { db } from '@/lib/db'; | ||
| import { users } from '@/lib/schema'; | ||
| import { eq } from 'drizzle-orm'; | ||
|
|
||
| export async function GET( | ||
| request: Request, | ||
| { params }: { params: { id: string } } | ||
| ) { | ||
| const user = await db | ||
| .select() | ||
| .from(users) | ||
| .where(eq(users.id, params.id)) | ||
| .limit(1); | ||
|
|
||
| if (!user.length) { | ||
| return Response.json( | ||
| { error: 'User not found' }, | ||
| { status: 404 } | ||
| ); | ||
| } | ||
|
|
||
| return Response.json(user[0]); | ||
| } | ||
| ``` | ||
|
|
||
| ## Best Practices | ||
|
|
||
| - **Start small** - Begin with 2-3 parallel agents and scale up | ||
| - **Keep tasks focused** - Smaller, well-defined tasks work better | ||
| - **Use isolation** - Each workspace should be independent | ||
| - **Commit frequently** - Save progress in each workspace | ||
|
|
||
| ### Configuration Example | ||
|
|
||
| You can configure Superset with a simple config file: | ||
|
|
||
| ```json | ||
| { | ||
| "workspaces": { | ||
| "maxParallel": 10, | ||
| "defaultBranch": "main", | ||
| "autoCommit": true | ||
| }, | ||
| "agents": { | ||
| "model": "claude-sonnet-4-20250514", | ||
| "maxTokens": 8192 | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Conclusion | ||
|
|
||
| Parallel coding agents transform how you work with AI. Instead of waiting, you're always making progress on something. Give it a try and see how it changes your workflow. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file added
BIN
+326 KB
apps/marketing/public/blog/history-of-git-worktrees/worktrees-visualization.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+198 KB
apps/marketing/public/blog/introducing-superset/workspace-interface.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+11.4 MB
apps/marketing/public/blog/parallel-agents-guide/parallel-agents-demo.mov
Binary file not shown.
109 changes: 109 additions & 0 deletions
109
apps/marketing/src/app/blog/[slug]/components/BlogPostLayout/BlogPostLayout.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| "use client"; | ||
|
|
||
| import { ArrowLeft } from "lucide-react"; | ||
| import Link from "next/link"; | ||
| import type { ReactNode } from "react"; | ||
| import { AuthorAvatar } from "@/app/blog/components/AuthorAvatar"; | ||
| import { GridCross } from "@/app/blog/components/GridCross"; | ||
| import { type BlogPost, formatBlogDate, type TocItem } from "@/lib/blog-utils"; | ||
|
|
||
| interface BlogPostLayoutProps { | ||
| post: BlogPost; | ||
| toc: TocItem[]; | ||
| children: ReactNode; | ||
| } | ||
|
|
||
| export function BlogPostLayout({ post, children }: BlogPostLayoutProps) { | ||
| const formattedDate = formatBlogDate(post.date); | ||
|
|
||
| return ( | ||
| <article className="relative min-h-screen"> | ||
| {/* Grid background with dashed lines */} | ||
| <div | ||
| className="absolute inset-0 pointer-events-none" | ||
| style={{ | ||
| backgroundImage: ` | ||
| linear-gradient(to right, transparent 0%, transparent calc(50% - 384px), rgba(255,255,255,0.06) calc(50% - 384px), rgba(255,255,255,0.06) calc(50% - 383px), transparent calc(50% - 383px), transparent calc(50% + 383px), rgba(255,255,255,0.06) calc(50% + 383px), rgba(255,255,255,0.06) calc(50% + 384px), transparent calc(50% + 384px)) | ||
| `, | ||
| }} | ||
| /> | ||
|
|
||
| {/* Hero header */} | ||
| <header className="relative border-b border-border"> | ||
| <div className="max-w-3xl mx-auto px-6 pt-16 pb-10 md:pt-20 md:pb-12"> | ||
| {/* Grid crosses */} | ||
| <GridCross className="top-0 left-0" /> | ||
| <GridCross className="top-0 right-0" /> | ||
|
|
||
| <div className="text-center"> | ||
| <span className="text-sm font-mono text-muted-foreground uppercase tracking-wider"> | ||
| {post.category} | ||
| </span> | ||
|
|
||
| <h1 className="text-3xl md:text-4xl lg:text-5xl font-medium tracking-tight text-foreground mt-4 mb-4"> | ||
| {post.title} | ||
| </h1> | ||
|
|
||
| {post.description && ( | ||
| <p className="text-base md:text-lg text-muted-foreground max-w-2xl mx-auto mb-6"> | ||
| {post.description} | ||
| </p> | ||
| )} | ||
|
|
||
| <div className="flex items-center justify-center gap-3 text-sm text-muted-foreground"> | ||
| <AuthorAvatar | ||
| name={post.author} | ||
| title="Cofounder, Superset" | ||
| twitterHandle="avimakesrobots" | ||
| /> | ||
| <span className="text-foreground/70">{post.author}</span> | ||
| <span className="text-muted-foreground/50">·</span> | ||
| <time dateTime={post.date}>{formattedDate}</time> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| {/* Bottom crosses */} | ||
| <div className="max-w-3xl mx-auto px-6 relative"> | ||
| <GridCross className="bottom-0 left-0" /> | ||
| <GridCross className="bottom-0 right-0" /> | ||
| </div> | ||
| </header> | ||
|
|
||
| {/* Back link section */} | ||
| <div className="relative border-b border-border"> | ||
| <div className="max-w-3xl mx-auto px-6 py-4"> | ||
| <Link | ||
| href="/blog" | ||
| className="inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors" | ||
| > | ||
| <ArrowLeft className="h-4 w-4" /> | ||
| Back to Blog | ||
| </Link> | ||
| </div> | ||
| </div> | ||
|
|
||
| {/* Content */} | ||
| <div className="relative max-w-3xl mx-auto px-6 py-12"> | ||
| <div className="prose max-w-none">{children}</div> | ||
| </div> | ||
|
|
||
| {/* Footer */} | ||
| <footer className="relative border-t border-border"> | ||
| <div className="max-w-3xl mx-auto px-6 relative"> | ||
| <GridCross className="top-0 left-0" /> | ||
| <GridCross className="top-0 right-0" /> | ||
| </div> | ||
| <div className="max-w-3xl mx-auto px-6 py-10"> | ||
| <Link | ||
| href="/blog" | ||
| className="inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors" | ||
| > | ||
| <ArrowLeft className="h-4 w-4" /> | ||
| All posts | ||
| </Link> | ||
| </div> | ||
| </footer> | ||
| </article> | ||
| ); | ||
| } | ||
1 change: 1 addition & 0 deletions
1
apps/marketing/src/app/blog/[slug]/components/BlogPostLayout/index.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export { BlogPostLayout } from "./BlogPostLayout"; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded author metadata will be incorrect for different authors.
The
titleandtwitterHandleprops are hardcoded to "Cofounder, Superset" and "avimakesrobots" respectively, butnameusespost.author. If blog posts have different authors, this will display incorrect metadata.Consider either:
authorTitleandauthorTwitterfields to theBlogPostinterface and frontmatter🤖 Prompt for AI Agents