Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ For information on how to run each project, see the README in each directory.
| [Building effective agents](/building-effective-agents) | 5 different patterns for building effective AI agents with Trigger.dev; [Prompt chaining](/building-effective-agents/src/trigger/trigger/translate-copy.ts), [Routing](/building-effective-agents/src/trigger/trigger/routing-questions.ts), [Parallelization](/building-effective-agents/src/trigger/trigger/parallel-llm-calls.ts), [Orchestrator-workers](/building-effective-agents/src/trigger/trigger/orchestrator-workers.ts) |
| [Claude thinking chatbot](/claude-thinking-chatbot) | A chatbot that uses Claude's thinking capabilities to generate responses |
| [Claude agent SDK](/claude-agent-sdk-trigger) | A simple example of how to use the [Claude Agent SDK](https://docs.claude.com/en/docs/agent-sdk/overview) with Trigger.dev |
| [Claude agent GitHub wiki](/claude-agent-github-wiki) | AI-powered repository analyzer that lets you ask questions about any public GitHub repository using Anthropic's [Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview), with real-time streaming via [Trigger.dev Realtime](https://trigger.dev/docs/realtime/overview) |
| [Deep research agent using the AI SDK](/vercel-ai-sdk-deep-research-agent/) | An intelligent deep research agent using the Vercel [AI SDK](https://sdk.vercel.ai/docs/introduction) and Trigger.dev |
| [Monorepos](/monorepos) | Examples of using Trigger.dev in monorepo setups with [Turborepo](https://turbo.build/) and [Prisma](https://www.prisma.io/) |
| [Next.js server actions](/nextjs-server-actions) | A [Next.js app](https://nextjs.org/) that triggers Trigger.dev tasks using Server Actions |
Expand Down
8 changes: 8 additions & 0 deletions claude-agent-github-wiki/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Trigger.dev Configuration
# Get these from https://cloud.trigger.dev
TRIGGER_PROJECT_REF=your_project_ref
TRIGGER_SECRET_KEY=your_secret_key

# Claude API Key
# Get from https://console.anthropic.com
ANTHROPIC_API_KEY=your_anthropic_api_key
3 changes: 3 additions & 0 deletions claude-agent-github-wiki/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
62 changes: 62 additions & 0 deletions claude-agent-github-wiki/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

CLAUDE.md

postgres-data
# dependencies
node_modules
.pnp
.pnp.js

# testing
coverage

# next.js
.next/
out/
dist
packages/**/dist

# Tailwind
apps/**/styles/tailwind.css
packages/**/styles/tailwind.css

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env.docker
.docker/*.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# turbo
.turbo
.vercel
.cache
.env
.output
apps/**/public/build
.tests-container-id.txt
.sentryclirc
.buildt

**/tmp/
/test-results/
/playwright-report/
/playwright/.cache/

.cosine
.trigger
.tshy*
.yarn
*.tsbuildinfo
.claude
86 changes: 86 additions & 0 deletions claude-agent-github-wiki/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# GitHub repository analyzer agent using Claude and Trigger.dev

This demo shows how to build a simple AI-powered repository analyzer that lets you ask questions about any public GitHub repository, using [Trigger.dev](https://trigger.dev/) for workflow orchestration, streaming, and showing progress on the frontend and [Anthropic's Claude Agent SDK](https://platform.claude.com/docs/en/agent-sdk/overview) for the agentic loop.

## Demo video

<video src="https://content.trigger.dev/Claude%20GitHub%20Wiki-example.mp4" controls autoplay loop muted width="100%"></video>

## Tech stack

- [**Next.js**](https://nextjs.org/) – Frontend framework using the App Router
- [**Claude Agent SDK**](https://platform.claude.com/docs/en/agent-sdk/overview) – Anthropic's SDK for building AI agents; provides an agentic loop with shell, file, and search tools
- [**Trigger.dev**](https://trigger.dev/) – runs the agent in a long-running background task with real-time streaming to the frontend

## Features

- **Ask anything about any public repo** – Architecture, security vulnerabilities, API endpoints, testing strategies, etc.
- **Claude Agent SDK exploration** – Claude explores the codebase and provide detailed answers
- **Cancel anytime** – Abort long-running Trigger.dev task with cleanup
- **Trigger.dev Realtime streaming** – Watch Claude's analysis stream in as it's generated
- **Progress tracking using Trigger.dev Realtime** – See clone status, analysis progress, and repo size

## Setup & running locally

1. **Clone the repository**

```bash
git clone <repository-url>
cd claude-agent-github-wiki
```

2. **Install dependencies**

```bash
npm install
```

3. **Copy environment variables and configure**

```bash
cp .env.example .env
```

Fill in the required environment variables:

- `TRIGGER_SECRET_KEY` – Get this from the [Trigger.dev dashboard](https://cloud.trigger.dev/)
- `TRIGGER_PROJECT_REF` – Your Trigger.dev project ref (starts with `proj_`)
- `ANTHROPIC_API_KEY` – Get this from the [Anthropic Console](https://console.anthropic.com/)

4. **Start the development servers**

```bash
# Terminal 1: Start Next.js dev server
npm run dev

# Terminal 2: Start Trigger.dev CLI
npx trigger.dev@latest dev
```

Open [http://localhost:3000](http://localhost:3000)

## How it works

Trigger.dev orchestrates the repository analysis through a single long-running task:

1. **`analyzeRepo`** – Main task that:
- Clones the repository to a temp directory (shallow clone for speed)
- Spawns a Claude agent with file system tools
- Streams Claude's response to the frontend in real-time via Trigger.dev's Realtime Streams
- Cleans up the temp directory on completion or error

## Relevant code

- **Main analysis task** – Clones repo, runs Claude agent, streams response ([`trigger/analyze-repo.ts`](trigger/analyze-repo.ts))
- **Stream definition** – Typed stream for real-time text responses ([`trigger/agent-stream.ts`](trigger/agent-stream.ts))
- **API endpoint** – Triggers the task and returns a public access token ([`app/api/analyze-repo/route.ts`](app/api/analyze-repo/route.ts))
- **Response page** – Real-time streaming display with progress ([`app/response/[runId]/page.tsx`](app/response/[runId]/page.tsx))
- **Landing page** – Repository URL input with example repos ([`app/page.tsx`](app/page.tsx))
- **Trigger.dev config** – Project settings with external SDK bundle ([`trigger.config.ts`](trigger.config.ts))

## Learn more

- [**Trigger.dev Realtime Streams**](https://trigger.dev/docs/realtime/streams) – Stream data from tasks to your frontend
- [**Trigger.dev React Hooks**](https://trigger.dev/docs/realtime/react-hooks/overview) – `useRealtimeStream` for consuming streams
- [**Claude Agent SDK**](https://platform.claude.com/docs/en/agent-sdk/overview) – Run Claude with agentic tool usage
- [**Trigger.dev schemaTask**](https://trigger.dev/docs/tasks/schemaTask) – Type-safe task payloads with Zod
29 changes: 29 additions & 0 deletions claude-agent-github-wiki/app/api/abort/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { runs } from "@trigger.dev/sdk";
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
try {
const { runId } = await request.json();

// Validate input
if (!runId || typeof runId !== "string") {
return NextResponse.json(
{ error: "Run ID is required" },
{ status: 400 }
);
}

// Cancel the running task
// This will trigger the AbortController in the task, which propagates to the Claude agent
await runs.cancel(runId);

return NextResponse.json({ success: true });

} catch (error: any) {
console.error("Failed to abort task:", error);
return NextResponse.json(
{ error: error.message || "Failed to abort task" },
{ status: 500 }
);
}
}
54 changes: 54 additions & 0 deletions claude-agent-github-wiki/app/api/analyze-repo/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { tasks } from "@trigger.dev/sdk";
import type { analyzeRepo } from "@/trigger/analyze-repo";
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
try {
const { repoUrl, question } = await request.json();

// Validate inputs
if (!repoUrl || typeof repoUrl !== "string") {
return NextResponse.json(
{ error: "Repository URL is required" },
{ status: 400 },
);
}

if (!question || typeof question !== "string") {
return NextResponse.json(
{ error: "Question is required" },
{ status: 400 },
);
}

// Basic GitHub URL validation
const githubUrlPattern = /^https?:\/\/(www\.)?github\.com\/[\w-]+\/[\w.-]+/;
if (!githubUrlPattern.test(repoUrl)) {
return NextResponse.json(
{ error: "Invalid GitHub URL format" },
{ status: 400 },
);
}

// Trigger the analyze task
const handle = await tasks.trigger<typeof analyzeRepo>(
"analyze-repo",
{ repoUrl, question },
);

// Get public access token from handle (auto-generated, expires in 15 min)
const accessToken = handle.publicAccessToken;

// Return run details
return NextResponse.json({
runId: handle.id,
accessToken,
});
} catch (error: any) {
console.error("Failed to trigger analyze-repo task:", error);
return NextResponse.json(
{ error: error.message || "Failed to start analysis" },
{ status: 500 },
);
}
}
102 changes: 102 additions & 0 deletions claude-agent-github-wiki/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
}

@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
}

@layer base {
:root {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 89.8%;
--input: 0 0% 89.8%;
--ring: 0 0% 3.9%;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
--radius: 0.5rem;
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 0 0% 9%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 0% 83.1%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}

@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}

@keyframes bounce {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-0.5rem);
}
}

.animate-bounce {
animation: bounce 0.6s ease-in-out infinite;
}

.line-clamp-3 {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
22 changes: 22 additions & 0 deletions claude-agent-github-wiki/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import './globals.css';
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';

const inter = Inter({ subsets: ['latin'] });

export const metadata: Metadata = {
title: 'Repo Wiki Chat - Chat with any GitHub repository',
description: 'Ask questions about any GitHub repository and watch AI analyze the code in real-time with live reasoning and tool usage.',
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
);
}
Loading