A project management tool for AI research teams where the unit of work is the experiment, not the task.
Signal treats research sprints the way engineering teams treat development sprints — with structured hypothesis tracking, confidence scoring, version-controlled prompt bundles, and a formal handoff pipeline from research to engineering.
Most research teams manage their work in Notion docs, shared spreadsheets, or Jira boards that were built for engineers. Signal is purpose-built for AI research workflows:
- Each experiment begins with a structured hypothesis (If / Then / Measured By)
- Confidence is tracked as a 0–100 score across the sprint, not as binary done/not-done
- When an experiment converges, it produces a Handoff Bundle — a structured artifact that an engineer can implement without needing to read the research notes
- Prompt and model configurations are version-controlled via AVC (AI Version Control), capturing diffs between prompt versions alongside eval results
- Dead ends are treated as first-class knowledge: every archived experiment has an epitaph and is indexed for future search so the team never repeats failed approaches
- The Branch Graph visualizes how experiments fork from each other over time
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript 5 |
| Styling | Tailwind CSS 4 + CSS custom properties (design tokens) |
| Database | PostgreSQL via Neon (serverless) |
| ORM | Drizzle ORM |
| Auth | Auth.js v5 (next-auth@beta) with Google + GitHub OAuth |
| Charts | Recharts 3 |
| Graph | @xyflow/react (React Flow v12) |
| Rich text | Tiptap 3 |
| Drag & drop | @dnd-kit |
| Icons | Lucide React |
| Deployment | Vercel |
src/
├── app/
│ ├── (auth)/
│ │ └── login/ # OAuth login page
│ ├── (dashboard)/
│ │ ├── layout.tsx # Sidebar + topbar shell
│ │ ├── board/ # Kanban experiment board
│ │ ├── experiments/[id]/ # Experiment detail (7 tabs)
│ │ ├── handoffs/ # Handoff queue + detail
│ │ ├── handoffs/[id]/
│ │ ├── avc/ # AVC bundle list
│ │ ├── avc/[bundleId]/ # Bundle detail
│ │ ├── avc/diff/ # Side-by-side prompt diff
│ │ ├── registry/ # Dead ends registry
│ │ ├── registry/[id]/ # Dead end detail
│ │ ├── graph/ # Branch graph (React Flow)
│ │ ├── reports/ # Sprint report
│ │ ├── lead/ # Lead dashboard
│ │ ├── sprints/ # Sprint management
│ │ ├── team/ # Team members
│ │ ├── integrations/ # Integrations
│ │ └── settings/ # Workspace settings
│ ├── api/auth/ # Auth.js route handler
│ └── layout.tsx # Root layout
├── components/
│ ├── board/ # Kanban board components
│ ├── experiments/detail/ # Per-tab experiment components
│ ├── shell/ # Sidebar + topbar
│ ├── shared/ # ConfidenceBar, StatusBadge
│ └── ui/ # Shadcn/base UI primitives
├── lib/
│ ├── auth.ts # Auth.js config
│ ├── db/
│ │ ├── index.ts # Drizzle + Neon client
│ │ └── schema.ts # Full Drizzle schema (25+ tables)
│ ├── actions/ # Server actions (experiments, handoffs)
│ ├── queries/ # DB query functions
│ ├── session.ts # Auth helpers (getCurrentUser, requireAuth)
│ ├── mock-*.ts # Mock data (used as fallback when no DB)
│ └── utils.ts
├── middleware.ts # Auth.js route protection
scripts/
└── seed.ts # Database seed script (Sprint 14 sample data)
| Route | Description |
|---|---|
/lead |
Lead dashboard — KPIs, sprint countdown, handoff funnel, team pulse, alerts |
/board |
Kanban board — experiments organized by status (Draft / Running / Converged / Branched / Stale) |
/sprints |
Sprint management — three-panel layout with sprint list, sprint detail, and planning backlog |
/handoffs |
Handoff queue — ready, blocked, in-progress, and shipped handoffs |
/handoffs/[id] |
Handoff detail — implementation brief, failed paths, AVC bundle, confidence history |
/graph |
Branch graph — interactive React Flow canvas showing experiment lineage in Temporal, Tree, or Cluster layout |
/avc |
AVC bundle list — all prompt/model snapshots grouped by experiment |
/avc/[bundleId] |
Bundle detail — prompt version, eval suite, model config, tool definitions |
/avc/diff |
Prompt diff — side-by-side diff between two AVC bundle versions with eval delta panel |
| Route | Description |
|---|---|
/registry |
Dead ends registry — searchable archive of failed experiments with Keyword, Semantic, and Variable search modes |
/registry/[id] |
Dead end detail — epitaph, hypothesis, result summary, confidence arc, related entries |
/reports |
Sprint report — AI summary, stat cards, confidence snapshot chart, learnings, handoffs, in-flight experiments, scorecard |
| Route | Description |
|---|---|
/team |
Team members — roles, invite panel, per-member experiment stats |
/integrations |
Integrations — GitHub, Slack, W&B, Notion, Linear, MLflow connections |
/settings |
Settings — General, Notifications, Appearance, Data & Export tabs |
Signal uses 25+ PostgreSQL tables across 7 domains:
Auth — users, accounts, sessions, verification_tokens (Auth.js managed)
Workspace — workspaces, workspace_members (roles: researcher / engineer / lead)
Sprints — sprints (active/closed, configurable decay/stale thresholds)
Experiments — experiments, confidence_snapshots, team_votes, result_entries, learnings, open_questions
Handoffs — handoffs, failed_paths, handoff_dependencies
AVC — avc_bundles, prompt_versions, few_shot_examples, model_configs, eval_suites, eval_cases, tool_definitions, annotations
Registry — dead_end_entries, dead_end_relations
Misc — sprint_reports, activity_log, notifications, integrations, api_keys
- Node.js 20+
- A Neon database (free tier works)
- Google OAuth app or GitHub OAuth app (or both)
git clone https://github.com/s3ak6i-dev/Signal.git
cd Signal
npm installCreate .env.local in the project root:
# Database (Neon)
DATABASE_URL=postgresql://user:password@host/dbname?sslmode=require
# Auth.js
AUTH_SECRET=your-random-32-char-secret
# Google OAuth (optional)
AUTH_GOOGLE_ID=your-google-client-id
AUTH_GOOGLE_SECRET=your-google-client-secret
# GitHub OAuth (optional)
AUTH_GITHUB_ID=your-github-client-id
AUTH_GITHUB_SECRET=your-github-client-secretGenerate AUTH_SECRET with:
npx auth secretnpm run db:pushThis runs drizzle-kit push which creates all tables in your Neon database without generating migration files.
npx tsx scripts/seed.tsSeeds Sprint 14 with:
- 4 team members (Surya, James, Mia, Priya)
- 1 workspace
- 11 experiments with confidence snapshots, results, and learnings
- Parent-child experiment relationships
- 2 handoffs (1 ready, 1 blocked)
npm run devOpen http://localhost:3000. The app redirects to /login. Sign in with Google or GitHub.
Without a database: The board page falls back to mock data automatically. Most pages work off mock data so you can explore the UI without credentials.
npm run dev # Start dev server with Turbopack
npm run build # Production build
npm run start # Start production server
npm run lint # Run ESLint
npm run db:push # Push schema to database (no migrations)
npm run db:generate # Generate Drizzle migration files
npm run db:migrate # Apply migration files
npm run db:studio # Open Drizzle Studio (local DB GUI)
npx tsx scripts/seed.ts # Seed sample dataSignal uses a dark design system with CSS custom properties. All tokens are defined in src/app/globals.css.
Color tokens
--bg: #080a0e /* Page background */
--surface-1: #0d1117 /* Card background */
--surface-2: #161b22 /* Elevated surface */
--surface-3: #1c2128 /* Highest surface */
--signal-accent: #3b8eea /* Primary accent (blue) */
--border-default: rgba(255,255,255,0.08)
--text-primary: #e6edf3
--text-secondary: #8b949e
--text-muted: #656d76Status colors
--status-converged: #22c55e
--status-running: #3b8eea
--status-branched: #f59e0b
--status-stale: #ef4444
--status-draft: #656d76Typography
- Body: Inter (
--font-inter) - Metrics and refs: JetBrains Mono (
--font-jetbrains-mono)
Hard constraints — no gradients, no drop shadows (accent glow only), no blur, no emoji.
- Go to Google Cloud Console → APIs & Services → Credentials
- Create an OAuth 2.0 Client ID (Web application)
- Authorized redirect URI:
http://localhost:3000/api/auth/callback/google - Copy Client ID and Secret to
.env.local
- Go to GitHub Settings → Developer settings → OAuth Apps → New OAuth App
- Homepage URL:
http://localhost:3000 - Callback URL:
http://localhost:3000/api/auth/callback/github - Copy Client ID and Secret to
.env.local
The project is configured for Vercel deployment.
- Push to GitHub
- Import the repo in Vercel
- Add all environment variables from
.env.localto the Vercel project settings - Deploy — Vercel detects Next.js automatically
For production OAuth, update redirect URIs in your Google/GitHub apps to use your production domain (e.g., https://yourdomain.vercel.app/api/auth/callback/google).
Mock data fallback — Every page that hits the database wraps the query in a try/catch and falls back to mock data. This means the UI is explorable without credentials, and the app degrades gracefully during database outages.
No Drizzle relations defined — Queries use Drizzle's select().from().leftJoin() API rather than the relational db.query.xxx.findMany({ with: {...} }) API. This avoids needing to define relations() while keeping queries explicit and composable.
Server actions for mutations — All writes go through "use server" functions in src/lib/actions/. Each action calls requireAuth(), performs the write, logs to activityLog, and calls revalidatePath to invalidate the Next.js cache.
Auth.js v5 middleware — src/middleware.ts protects all routes under /(dashboard) and redirects unauthenticated users to /login with a callbackUrl parameter.
Confidence as a time series — Experiment confidence is stored as a confidence_snapshots table rather than a single column on the experiment. This enables trend charts, decay detection, and sprint-over-sprint comparison.