From 58cd7425ed969746b4585a4fa99d732d80237c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Flor=C3=AAncio?= Date: Sat, 17 Jan 2026 23:48:23 +0000 Subject: [PATCH] feat: improve landing page (#33) --- apps/landing/app/blog/page.tsx | 49 +- apps/landing/app/changelog/[slug]/page.tsx | 61 +++ apps/landing/app/changelog/page.tsx | 70 +++ apps/landing/app/docs/agents/page.tsx | 35 ++ apps/landing/app/docs/boards/page.tsx | 51 ++ apps/landing/app/docs/docker/page.tsx | 36 ++ apps/landing/app/docs/installation/page.tsx | 42 ++ apps/landing/app/docs/layout.tsx | 8 +- apps/landing/app/docs/page.tsx | 188 ++----- apps/landing/app/docs/quick-start/page.tsx | 46 ++ apps/landing/app/docs/tasks/page.tsx | 42 ++ apps/landing/app/docs/workspaces/page.tsx | 42 ++ apps/landing/app/docs/worktrees/page.tsx | 40 ++ apps/landing/components/changelog-video.tsx | 28 ++ apps/landing/components/docs-card.tsx | 26 + apps/landing/components/docs-code.tsx | 9 + apps/landing/components/docs-shell.tsx | 25 + apps/landing/components/docs-sidebar.tsx | 23 +- apps/landing/components/footer.tsx | 4 +- apps/landing/components/hero-section.tsx | 86 ++-- apps/landing/components/mdx-components.tsx | 44 ++ apps/landing/components/navbar.tsx | 6 +- .../changelog/2026-01-17-launch/index.mdx | 37 ++ apps/landing/lib/changelog.ts | 71 +++ apps/landing/next-env.d.ts | 2 +- apps/landing/package.json | 2 + .../2026-01-17-launch/high-level-flow.svg | 18 + .../2026-01-17-launch/launch-hero.svg | 14 + apps/pnpm-lock.yaml | 472 +++++++++++++++++- 29 files changed, 1307 insertions(+), 270 deletions(-) create mode 100644 apps/landing/app/changelog/[slug]/page.tsx create mode 100644 apps/landing/app/changelog/page.tsx create mode 100644 apps/landing/app/docs/agents/page.tsx create mode 100644 apps/landing/app/docs/boards/page.tsx create mode 100644 apps/landing/app/docs/docker/page.tsx create mode 100644 apps/landing/app/docs/installation/page.tsx create mode 100644 apps/landing/app/docs/quick-start/page.tsx create mode 100644 apps/landing/app/docs/tasks/page.tsx create mode 100644 apps/landing/app/docs/workspaces/page.tsx create mode 100644 apps/landing/app/docs/worktrees/page.tsx create mode 100644 apps/landing/components/changelog-video.tsx create mode 100644 apps/landing/components/docs-card.tsx create mode 100644 apps/landing/components/docs-code.tsx create mode 100644 apps/landing/components/docs-shell.tsx create mode 100644 apps/landing/components/mdx-components.tsx create mode 100644 apps/landing/content/changelog/2026-01-17-launch/index.mdx create mode 100644 apps/landing/lib/changelog.ts create mode 100644 apps/landing/public/changelog/2026-01-17-launch/high-level-flow.svg create mode 100644 apps/landing/public/changelog/2026-01-17-launch/launch-hero.svg diff --git a/apps/landing/app/blog/page.tsx b/apps/landing/app/blog/page.tsx index 5bfa3e4265..ef9aecc3fd 100644 --- a/apps/landing/app/blog/page.tsx +++ b/apps/landing/app/blog/page.tsx @@ -1,50 +1,5 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@kandev/ui/card'; -import Link from 'next/link'; - -const blogPosts = [ - { - title: 'Introducing kandev.ai: AI-Powered Kanban for Developers', - description: 'Learn how kandev.ai combines Kanban boards with AI agents, isolated worktrees, and Docker containers to accelerate your development workflow.', - date: 'January 10, 2026', - slug: 'introducing-kandev', - author: 'Kandev Team', - }, - { - title: 'Running Multiple AI Agents in Parallel: Best Practices', - description: 'Discover how to effectively manage multiple AI coding agents working simultaneously on different tasks using isolated environments and approval workflows.', - date: 'January 5, 2026', - slug: 'parallel-ai-agents', - author: 'Kandev Team', - }, -]; +import { redirect } from 'next/navigation'; export default function BlogPage() { - return ( -
-

Blog

-

- Insights and updates from the kandev.ai team. -

- -
- {blogPosts.map((post) => ( - - - -
- {post.date} - • - {post.author} -
- {post.title} -
- - {post.description} - -
- - ))} -
-
- ); + redirect('/changelog'); } diff --git a/apps/landing/app/changelog/[slug]/page.tsx b/apps/landing/app/changelog/[slug]/page.tsx new file mode 100644 index 0000000000..057c8ce834 --- /dev/null +++ b/apps/landing/app/changelog/[slug]/page.tsx @@ -0,0 +1,61 @@ +import { notFound } from 'next/navigation'; +import { MDXRemote } from 'next-mdx-remote/rsc'; +import { getChangelogEntry, getChangelogSlugs } from '@/lib/changelog'; +import { mdxComponents } from '@/components/mdx-components'; + +function formatDate(date: string) { + if (!date) return ''; + return new Intl.DateTimeFormat('en-US', { + month: 'long', + day: 'numeric', + year: 'numeric', + }).format(new Date(date)); +} + +export async function generateStaticParams() { + const slugs = await getChangelogSlugs(); + return slugs.map((slug) => ({ slug })); +} + +export default async function ChangelogEntryPage({ + params, +}: { + params: { slug?: string } | Promise<{ slug?: string }>; +}) { + const resolvedParams = await Promise.resolve(params); + const slug = resolvedParams.slug; + + if (!slug) { + notFound(); + } + const entry = await getChangelogEntry(slug); + + if (!entry) { + notFound(); + } + + return ( +
+
+
+
+

{entry.surface}

+

{entry.title}

+

{formatDate(entry.date)}

+
+ +
+ {entry.summary.map((line) => ( +

+ {line} +

+ ))} +
+ +
+ +
+
+
+ ); +} diff --git a/apps/landing/app/changelog/page.tsx b/apps/landing/app/changelog/page.tsx new file mode 100644 index 0000000000..b41513c643 --- /dev/null +++ b/apps/landing/app/changelog/page.tsx @@ -0,0 +1,70 @@ +import Link from 'next/link'; +import { getChangelogEntries } from '@/lib/changelog'; + +function formatDate(date: string) { + if (!date) return ''; + return new Intl.DateTimeFormat('en-US', { + month: 'long', + day: 'numeric', + year: 'numeric', + }).format(new Date(date)); +} + +export default async function ChangelogPage() { + const entries = await getChangelogEntries(); + + return ( +
+
+
+
+

Changelog

+

Product updates

+

+ A running log of kandev.ai releases, shipped features, and operational improvements. +

+
+ +
+ {entries.map((entry, index) => ( +
+
+

{entry.surface}

+

{formatDate(entry.date)}

+ {index === 0 ? ( + + Latest + + ) : null} +
+ +
+

+ + {entry.title} + +

+
+ {entry.summary.map((line) => ( +

{line}

+ ))} +
+
+ + Read full update → + +
+
+
+ ))} +
+
+
+ ); +} diff --git a/apps/landing/app/docs/agents/page.tsx b/apps/landing/app/docs/agents/page.tsx new file mode 100644 index 0000000000..8d02066c1f --- /dev/null +++ b/apps/landing/app/docs/agents/page.tsx @@ -0,0 +1,35 @@ +import { DocsShell } from '@/components/docs-shell'; +import { DocsCard } from '@/components/docs-card'; +import { DocsCode } from '@/components/docs-code'; + +export default function AgentsDocsPage() { + return ( + +
+ +
    +
  1. Container starts with agentctl on port 9999.
  2. +
  3. Backend calls initialize and session/new.
  4. +
  5. Tasks are sent via session/prompt.
  6. +
  7. Agent streams session/update notifications.
  8. +
+
+ +
    +
  • Read and edit files inside the worktree
  • +
  • Run shell commands with approval gates
  • +
  • Stream progress updates to the UI
  • +
+
+
+ + + {`{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"1.0"}}`} + +
+ ); +} diff --git a/apps/landing/app/docs/boards/page.tsx b/apps/landing/app/docs/boards/page.tsx new file mode 100644 index 0000000000..7e531db73a --- /dev/null +++ b/apps/landing/app/docs/boards/page.tsx @@ -0,0 +1,51 @@ +import { DocsShell } from '@/components/docs-shell'; +import { DocsCard } from '@/components/docs-card'; +import { DocsCode } from '@/components/docs-code'; + +const stages = [ + { title: 'Backlog', desc: 'Collect ideas and future work.' }, + { title: 'In Progress', desc: 'Active tasks owned by agents.' }, + { title: 'Review', desc: 'Approvals and QA before merge.' }, + { title: 'Done', desc: 'Completed and shipped items.' }, +]; + +export default function BoardsDocsPage() { + return ( + +
+ {stages.map((stage) => ( + +

{stage.desc}

+
+ ))} +
+ + +

Keep columns minimal and apply WIP limits where review capacity is tight.

+ {`board: + name: "Product Roadmap" + columns: + - name: "Backlog" + wipLimit: null + - name: "In Progress" + wipLimit: 4 + - name: "Review" + wipLimit: 2 + - name: "Done" + wipLimit: null`} +
+ + +
    +
  • Use a single “Review” column so approvals are centralized.
  • +
  • Keep WIP limits low to prevent agent overload.
  • +
  • Archive finished tasks weekly to keep focus on active work.
  • +
+
+
+ ); +} diff --git a/apps/landing/app/docs/docker/page.tsx b/apps/landing/app/docs/docker/page.tsx new file mode 100644 index 0000000000..b719665017 --- /dev/null +++ b/apps/landing/app/docs/docker/page.tsx @@ -0,0 +1,36 @@ +import { DocsShell } from '@/components/docs-shell'; +import { DocsCard } from '@/components/docs-card'; +import { DocsCode } from '@/components/docs-code'; + +export default function DockerDocsPage() { + return ( + +
+ +
    +
  • /workspace — your repository worktree
  • +
  • /root/.augment/sessions — agent session storage (when enabled)
  • +
+
+ +
    +
  1. Consistent, reproducible environments
  2. +
  3. Security boundaries for file and network access
  4. +
  5. Easy cleanup after task completion
  6. +
+
+
+ + + {`docker run -it --rm \ + -v /path/to/repo:/workspace \ + -e TASK_DESCRIPTION="Fix the login bug" \ + kandev/augment-agent:latest`} + +
+ ); +} diff --git a/apps/landing/app/docs/installation/page.tsx b/apps/landing/app/docs/installation/page.tsx new file mode 100644 index 0000000000..868bc61c5c --- /dev/null +++ b/apps/landing/app/docs/installation/page.tsx @@ -0,0 +1,42 @@ +import { DocsShell } from '@/components/docs-shell'; +import { DocsCard } from '@/components/docs-card'; +import { DocsCode } from '@/components/docs-code'; + +export default function InstallationDocsPage() { + return ( + +
+ +
    +
  • Docker Desktop (or Docker Engine)
  • +
  • Git 2.30+
  • +
  • Node.js 20+
  • +
+
+ + {`git clone https://github.com/kdlbs/kandev.git +cd kandev +pnpm install`} + +
+ + +

Start the backend, app, and landing site in separate terminals.

+ {`pnpm --filter @kandev/backend dev +pnpm --filter @kandev/web dev +pnpm --filter @kandev/landing dev`} +
+ + +

+ Open the UI and create a test workspace. The system should start an agent container on demand and stream + progress back over WebSocket. +

+
+
+ ); +} diff --git a/apps/landing/app/docs/layout.tsx b/apps/landing/app/docs/layout.tsx index ec1602ac03..c4a742812c 100644 --- a/apps/landing/app/docs/layout.tsx +++ b/apps/landing/app/docs/layout.tsx @@ -2,9 +2,11 @@ import { DocsSidebar } from '@/components/docs-sidebar'; export default function DocsLayout({ children }: { children: React.ReactNode }) { return ( -
- -
{children}
+
+
+ +
{children}
+
); } diff --git a/apps/landing/app/docs/page.tsx b/apps/landing/app/docs/page.tsx index 8d9e025f3c..fdb06a91ed 100644 --- a/apps/landing/app/docs/page.tsx +++ b/apps/landing/app/docs/page.tsx @@ -1,149 +1,51 @@ +import { DocsShell } from '@/components/docs-shell'; +import { DocsCard } from '@/components/docs-card'; +import { DocsCode } from '@/components/docs-code'; + export default function DocsPage() { return ( -
-
-

Getting Started with kandev.ai

-

- kandev.ai combines Kanban task management with AI-powered development workflows. Manage tasks visually, - execute them with AI agents in isolated environments, and ship faster with confidence. -

-
+ +
+ +

+ kandev.ai is a WebSocket-first platform that pairs Kanban task management with AI-assisted execution. + Every task runs inside a dedicated git worktree and a Docker container, with approvals for sensitive + operations. +

+
+ +
    +
  • Ship in parallel without branch conflicts.
  • +
  • Keep execution auditable and reviewable.
  • +
  • Stream progress updates in real time.
  • +
+
+
-
-

What is kandev.ai?

-

- kandev.ai is a development tool that bridges project management and AI-assisted coding. Each task on your - Kanban board can be executed by AI agents working in isolated git worktrees and Docker containers. -

-
+ +

From task creation to approval, kandev.ai follows a consistent loop.

+ {`1. Create task on the board +2. Start agent container via agentctl +3. Initialize ACP session +4. Stream progress over WebSocket +5. Review and approve output`} +
-

Key Features

-
-
-

Visual Task Management

-

Organize development work with Kanban boards

-
-
-

Isolated Worktrees

-

Each task gets its own git worktree for parallel development

-
-
-

Local Docker Execution

-

AI agents run in secure Docker containers on your machine

-
-
-

Multiple AI Agents

-

Support for Claude Code, OpenAI Codex, Augment, and more

-
-
-

Approval Workflows

-

Review and approve agent changes before merging

-
-
-

Multiple Workspaces

-

Organize projects by client, team, or product

-
-
- -

How It Works

-
-
-
1
-
-

Create a Task

-

Add a task to your Kanban board with a description of what needs to be done

-
-
-
-
2
-
-

Configure Repository

-

Select a repository and base branch for the task

-
-
-
-
3
-
-

Choose AI Agent

-

Select which AI agent should work on the task

-
-
-
-
4
-
-

Isolated Environment

-

kandev creates an isolated git worktree and Docker container

-
-
-
-
5
-
-

AI Execution

-

The AI agent executes the task in the secure environment

-
-
-
-
6
-
-

Review & Approve

-

Review the changes and approve them for merging

-
-
-
- -
-

Why kandev.ai?

-

- Traditional development workflows require constant context switching. kandev.ai eliminates this by: -

-
    -
  • - ✓ - Visualizing all work in progress on a single board -
  • -
  • - ✓ - Enabling parallel development without branch conflicts -
  • -
  • - ✓ - Automating routine tasks with AI agents -
  • -
  • - ✓ - Maintaining security through isolated execution environments -
  • -
-
- -
-

Security & Control

-

- Every operation performed by AI agents is logged and requires approval. Agents run in isolated Docker - containers with restricted permissions, ensuring your codebase and system remain secure. -

-
- -
-

Ready to Get Started?

-

- Check out our guides to install and configure kandev.ai -

- -
-
+
+ +

Group repositories, boards, and team settings.

+
+ +

Model your workflow with Kanban columns.

+
+ +

Define the scope, constraints, and agent requirements.

+
+
+ ); } diff --git a/apps/landing/app/docs/quick-start/page.tsx b/apps/landing/app/docs/quick-start/page.tsx new file mode 100644 index 0000000000..bf570d91d4 --- /dev/null +++ b/apps/landing/app/docs/quick-start/page.tsx @@ -0,0 +1,46 @@ +import { DocsShell } from '@/components/docs-shell'; +import { DocsCard } from '@/components/docs-card'; +import { DocsCode } from '@/components/docs-code'; + +const steps = [ + { + step: '1. Create a workspace', + body: 'Create a workspace for the repository you want to manage.', + }, + { + step: '2. Add a board and task', + body: 'Add a board with columns, then create a task that describes the desired change.', + }, + { + step: '3. Run an agent', + body: 'Start an agent from the task. The UI should stream progress updates as the agent works.', + }, + { + step: '4. Review and merge', + body: 'Review the diff, approve any gated actions, and merge the worktree.', + }, +]; + +export default function QuickStartDocsPage() { + return ( + +
+ {steps.map((item) => ( + +

{item.body}

+
+ ))} +
+ + + {`Task: Update onboarding copy +Constraints: Touch only apps/landing +Acceptance: Copy updated and passes lint`} + +
+ ); +} diff --git a/apps/landing/app/docs/tasks/page.tsx b/apps/landing/app/docs/tasks/page.tsx new file mode 100644 index 0000000000..9e9874bdd5 --- /dev/null +++ b/apps/landing/app/docs/tasks/page.tsx @@ -0,0 +1,42 @@ +import { DocsShell } from '@/components/docs-shell'; +import { DocsCard } from '@/components/docs-card'; +import { DocsCode } from '@/components/docs-code'; + +export default function TasksDocsPage() { + return ( + +
+ +
    +
  • Title and description
  • +
  • Priority and due date
  • +
  • Repository and base branch
  • +
  • Agent type and environment
  • +
  • Approval requirements
  • +
+
+ +
    +
  1. State the outcome, not the steps.
  2. +
  3. Call out sensitive files or commands.
  4. +
  5. Include acceptance criteria.
  6. +
+
+
+ + + {`Title: Add changelog page +Repo: github.com/kdlbs/kandev +Branch: main +Agent: augment-agent +Goal: Replace blog with changelog +Constraints: Keep existing navbar/footer +Output: New route + MDX entries`} + +
+ ); +} diff --git a/apps/landing/app/docs/workspaces/page.tsx b/apps/landing/app/docs/workspaces/page.tsx new file mode 100644 index 0000000000..0090bea1d3 --- /dev/null +++ b/apps/landing/app/docs/workspaces/page.tsx @@ -0,0 +1,42 @@ +import { DocsShell } from '@/components/docs-shell'; +import { DocsCard } from '@/components/docs-card'; +import { DocsCode } from '@/components/docs-code'; + +export default function WorkspacesDocsPage() { + return ( + +
+ +
    +
  • Boards that define workflow stages
  • +
  • Repositories connected to those boards
  • +
  • Default agent settings and approvals
  • +
  • Member roles and permissions
  • +
+
+ +
    +
  1. Use one workspace per product or client.
  2. +
  3. Keep board naming consistent across teams.
  4. +
  5. Set approvals at the workspace level.
  6. +
+
+
+ + +

A workspace keeps everything organized in one place.

+ {`Workspace: "Core Platform" +Boards: + - Product Roadmap + - Incident Response +Repositories: + - github.com/kdlbs/kandev + - github.com/kdlbs/kandev-docs`} +
+
+ ); +} diff --git a/apps/landing/app/docs/worktrees/page.tsx b/apps/landing/app/docs/worktrees/page.tsx new file mode 100644 index 0000000000..4055eb9972 --- /dev/null +++ b/apps/landing/app/docs/worktrees/page.tsx @@ -0,0 +1,40 @@ +import { DocsShell } from '@/components/docs-shell'; +import { DocsCard } from '@/components/docs-card'; +import { DocsCode } from '@/components/docs-code'; + +const benefits = [ + { title: 'Parallel tasks', desc: 'Multiple agents can work without branch collisions.' }, + { title: 'Clean diffs', desc: 'Each task produces an isolated patch.' }, + { title: 'Fast setup', desc: 'No extra clones required.' }, +]; + +export default function WorktreesDocsPage() { + return ( + +
+ {benefits.map((item) => ( + +

{item.desc}

+
+ ))} +
+ + + {`/repos/kandev + /main (primary checkout) + /.worktrees/task-123 + /.worktrees/task-124`} + + + +

+ When a task is completed and merged, the worktree can be safely removed without affecting the main checkout. +

+
+
+ ); +} diff --git a/apps/landing/components/changelog-video.tsx b/apps/landing/components/changelog-video.tsx new file mode 100644 index 0000000000..76c3072b33 --- /dev/null +++ b/apps/landing/components/changelog-video.tsx @@ -0,0 +1,28 @@ +import type { HTMLAttributes } from 'react'; + +type ChangelogVideoProps = { + src: string; + poster?: string; + caption?: string; +} & HTMLAttributes; + +export function ChangelogVideo({ src, poster, caption, className, ...props }: ChangelogVideoProps) { + return ( +
+
+ ); +} diff --git a/apps/landing/components/docs-card.tsx b/apps/landing/components/docs-card.tsx new file mode 100644 index 0000000000..6e79e5a0a2 --- /dev/null +++ b/apps/landing/components/docs-card.tsx @@ -0,0 +1,26 @@ +import type { ReactNode } from 'react'; + +export function DocsCard({ + title, + children, + variant = 'default', +}: { + title: string; + children: ReactNode; + variant?: 'default' | 'accent' | 'muted'; +}) { + const base = + 'rounded-2xl border border-border/60 bg-card/50 p-6 shadow-[0_12px_40px_-28px_rgba(37,99,235,0.5)] backdrop-blur'; + const variants: Record = { + default: 'bg-card/50', + accent: 'border-primary/30 bg-primary/10', + muted: 'bg-muted/30', + }; + + return ( +
+

{title}

+
{children}
+
+ ); +} diff --git a/apps/landing/components/docs-code.tsx b/apps/landing/components/docs-code.tsx new file mode 100644 index 0000000000..cb7bf808cd --- /dev/null +++ b/apps/landing/components/docs-code.tsx @@ -0,0 +1,9 @@ +import type { ReactNode } from 'react'; + +export function DocsCode({ children }: { children: ReactNode }) { + return ( +
+      {children}
+    
+ ); +} diff --git a/apps/landing/components/docs-shell.tsx b/apps/landing/components/docs-shell.tsx new file mode 100644 index 0000000000..4ffbff80f8 --- /dev/null +++ b/apps/landing/components/docs-shell.tsx @@ -0,0 +1,25 @@ +export function DocsShell({ + eyebrow, + title, + description, + children, +}: { + eyebrow: string; + title: string; + description: string; + children: React.ReactNode; +}) { + return ( +
+
+
+
+

{eyebrow}

+

{title}

+

{description}

+
+ {children} +
+
+ ); +} diff --git a/apps/landing/components/docs-sidebar.tsx b/apps/landing/components/docs-sidebar.tsx index 0a6721196c..f75cee0901 100644 --- a/apps/landing/components/docs-sidebar.tsx +++ b/apps/landing/components/docs-sidebar.tsx @@ -29,34 +29,13 @@ const sections = [ { title: 'Docker Execution', href: '/docs/docker' }, ], }, - { - title: 'Integrations', - items: [ - { title: 'MCP Servers', href: '/docs/mcp' }, - { title: 'GitHub', href: '/docs/github' }, - ], - }, - { - title: 'Security', - items: [ - { title: 'Approval Workflows', href: '/docs/approvals' }, - { title: 'Audit Logs', href: '/docs/audit-logs' }, - ], - }, - { - title: 'Advanced', - items: [ - { title: 'Configuration', href: '/docs/configuration' }, - { title: 'CLI Reference', href: '/docs/cli' }, - ], - }, ]; export function DocsSidebar() { const pathname = usePathname(); return ( -