From 27825e9b303448cc5f3d7b5e99f82b1eeb8131ae Mon Sep 17 00:00:00 2001
From: Abou Kone
Date: Wed, 21 Jan 2026 12:35:28 -0500
Subject: [PATCH 1/5] docs: update implementation status and add technical
documentation
- Update status markers across multiple PRDs and implementation trackers
- Add new technical documentation for analysis pipeline and how vibed works
- Correct Supabase Studio port number in setup guide
- Document migration from Edge Functions to Inngest for job processing
---
Agents.md | 10 +-
docs/PRD-profile-aggregation.md | 5 +
docs/PRD-vibed-ux.md | 4 +-
docs/PRD-vibed.md | 22 +-
docs/PRD.md | 146 ++--
docs/WorkflowJournal.md | 4 +-
docs/architecture/overview.md | 7 +-
docs/architecture/vibed-analysis-pipeline.md | 852 +++++++++++++++++++
docs/github-setup.md | 2 +-
docs/how-vibed-works.md | 187 ++++
docs/implementation-trackers/vibed.md | 52 +-
docs/prd/multi-agent-detection.md | 2 +-
docs/research/ai-era-coding-personas.md | 11 +-
13 files changed, 1202 insertions(+), 102 deletions(-)
create mode 100644 docs/architecture/vibed-analysis-pipeline.md
create mode 100644 docs/how-vibed-works.md
diff --git a/Agents.md b/Agents.md
index b4ff47b..31b3ee0 100644
--- a/Agents.md
+++ b/Agents.md
@@ -12,10 +12,14 @@ This document provides instructions for AI agents working on the Vibed Coding co
- **Backend:** Next.js Route Handlers (Vercel)
- **Auth:** Supabase Auth with GitHub OAuth
- **Database:** Supabase Postgres with Row Level Security
-- **Background Jobs:** Supabase Edge Functions
-- **LLM:** Claude API (server-side only)
+- **Background Jobs:** Inngest (primary) or standalone worker (fallback)
+- **LLM:** Anthropic Claude, OpenAI, or Google Gemini (server-side only, configurable)
-See `docs/PRD.md` for full product requirements.
+See `docs/PRD.md` for full product requirements and `docs/architecture/inngest-integration.md` for job processing details.
+
+**Key Reference Docs:**
+- [How Vibed Works](docs/how-vibed-works.md) — Product-friendly explanation of analysis
+- [Vibed Analysis Pipeline](docs/architecture/vibed-analysis-pipeline.md) — Technical architecture with algorithms and data flow
---
diff --git a/docs/PRD-profile-aggregation.md b/docs/PRD-profile-aggregation.md
index 4862495..0b89948 100644
--- a/docs/PRD-profile-aggregation.md
+++ b/docs/PRD-profile-aggregation.md
@@ -1,5 +1,10 @@
# PRD: Profile Aggregation — One Persona Per User
+**Status:** Core Implementation Complete — See `docs/implementation-trackers/profile-aggregation.md` for details
+
+> **Reference Documentation:** For technical details on aggregation, see:
+> - [Vibed Analysis Pipeline](./architecture/vibed-analysis-pipeline.md#profile-aggregation) — Aggregation algorithm details
+
## The Problem
We built personas per repo. The PRDs say personas should aggregate per user.
diff --git a/docs/PRD-vibed-ux.md b/docs/PRD-vibed-ux.md
index 73a33b8..193f032 100644
--- a/docs/PRD-vibed-ux.md
+++ b/docs/PRD-vibed-ux.md
@@ -1,5 +1,7 @@
# PRD: Vibed UX — The Pop Version of Developer Analytics
+**Status:** Partially Implemented — Core persona detection and profile pages are live. Share cards and some UX polish items are in progress.
+
> "Run it once, discover something surprising about yourself, share it with a friend."
---
@@ -181,7 +183,7 @@ Every page in the application must reflect the Vibed personality. Here's the com
## 1. The Vision
-Vibed Coding should feel like taking a personality quiz that actually knows you — except it's based on real data from your commits. Think BuzzFeed meets Spotify Wrapped for developers. The user should laugh, nod in recognition, screenshot something, and text it to a coworker within 5 minutes of their first analysis.
+Vibed Coding should feel like taking a personality quiz that actually knows you, except it's based on real data from your commits. Think BuzzFeed meets Spotify Wrapped for vibe coders. The user should laugh, nod in recognition, screenshot something, and text it to a coworker within 5 minutes of their first analysis.
**What we're NOT building:**
- A performance review tool
diff --git a/docs/PRD-vibed.md b/docs/PRD-vibed.md
index 5d2c091..5605aa7 100644
--- a/docs/PRD-vibed.md
+++ b/docs/PRD-vibed.md
@@ -2,6 +2,12 @@
# PRD: Vibed Narrative Layer
+**Status:** Mostly Implemented — See `docs/implementation-trackers/vibed.md` for details
+
+> **Reference Documentation:** For technical details on how analysis works, see:
+> - [How Vibed Works](./how-vibed-works.md) — Product-friendly overview
+> - [Vibed Analysis Pipeline](./architecture/vibed-analysis-pipeline.md) — Technical architecture
+
## 1. Context & Vision
Bolokono now surfaces “vibe coding profiles” through the Vibed experience: a playful, reflective interpretation of commit history modeled on Spotify Wrapped. The goal is to make craftsmanship visible—narrative cards first, data second—while preserving trust through evidence-backed insights. This PRD defines the UX, UI, API, database, and worker investments required to deliver deterministic insights, persona-aware storytelling, and share-ready outputs.
@@ -14,9 +20,21 @@ Bolokono now surfaces “vibe coding profiles” through the Vibed experience: a
4. **Evidence & depth**: Keep a deep-dive layer with raw metrics, commit samples, evidence SHAs, and persona signal explanations for power users.
5. **Persona-aware confidence**: Surface persona tags + confidence metadata so insights stay observational (“You tend to…”, “Often, etc.”).
-## 3. Supporting Research Summary
+## 3. Supporting Research & Attribution
+
+### External Sources
+- **"Vibe coding"**: Term coined by [Andrej Karpathy](https://x.com/karpathy/status/1886192184808149383) (February 2025), [Collins Dictionary Word of the Year 2025](https://en.wikipedia.org/wiki/Vibe_coding).
+- **Orchestrator vs Conductor patterns**: [Addy Osmani's agentic coding research](https://addyosmani.com/blog/future-agentic-coding/).
+- **Code analytics**: [GitClear developer productivity studies](https://www.gitclear.com/).
+- **Copilot workflows**: [GitHub Copilot documentation](https://docs.github.com/en/copilot).
+
+### Internal Research
+- [AI-Era Coding Personas](./research/ai-era-coding-personas.md)
+- [AI-Era Developer Personas (ChatGPT synthesis)](./research/ai-era-developer-personas-chatgpt.md)
+- [Persona Insight Synthesis](./research/persona-insight-synthesis.md)
-Sources: `docs/research/ai-era-coding-personas.md`, `docs/research/ai-era-developer-personas-chatgpt.md`, `docs/research/persona-insight-synthesis.md`. Personas to detect: Spec-Driven Architect / Cautious Traditionalist, Test-First Validator / Pragmatic Augmenter, Iterative Prototyper / Vibe Coder, Multi-Agent Orchestrator / Autonomous AI Orchestrator, Specialist Consultant, Infrastructure Architect, Hands-On Debugger / Rapid Risk-Taker. Insights should mention craft behavior, guardrails, and risk tolerance.
+### Personas Detected
+Spec-Driven Architect, Test-First Validator, Vibe Prototyper, Agent Orchestrator, Hands-On Debugger, Rapid Risk-Taker, Reflective Balancer. Insights emphasize craft behavior, guardrails, and risk tolerance.
## 4. Metrics & Signals to Capture
diff --git a/docs/PRD.md b/docs/PRD.md
index c97dfdc..6bb3aaa 100644
--- a/docs/PRD.md
+++ b/docs/PRD.md
@@ -1,10 +1,16 @@
-# PRD: Bolokono
+# PRD: Bolokono (Vibed Coding)
-**Product name:** Bolokono
+**Product name:** Bolokono (publicly branded as **Vibed Coding**)
**Author:** Abou Kone
-**Status:** Draft v4 (Monorepo architecture)
+**Status:** Draft v4 (Monorepo architecture) — Core features implemented
**Audience:** Product, Engineering (human + AI agents)
+> **Terminology Note:** This PRD uses the original "Bolokono" terminology. In the codebase and user-facing product, this has been rebranded to **Vibed Coding**. "Bolokono types" are now called **Vibe Personas**, and "Bolokono profiles" are now **Vibe Profiles**. See `docs/PRD-vibed-ux.md` for the current UX direction.
+
+> **Reference Documentation:** For a complete explanation of how analysis works, see:
+> - [How Vibed Works](./how-vibed-works.md) — Product-friendly overview
+> - [Vibed Analysis Pipeline](./architecture/vibed-analysis-pipeline.md) — Technical architecture with diagrams
+
---
## 1. Product Story
@@ -153,22 +159,22 @@ They summarize computed facts and cite evidence.
**Includes:**
- [x] Authentication (GitHub OAuth via Supabase)
-- [ ] GitHub repository listing and selection
-- [ ] Database schema with RLS
-- [ ] Repository sync (metadata only)
-- [ ] Analysis job queue and state machine
-- [ ] Edge Function analyzer (commit metadata extraction)
-- [ ] Metrics computation and persistence
-- [ ] Minimal Bolokono profile generation
-- [ ] Basic report UI
+- [x] GitHub repository listing and selection
+- [x] Database schema with RLS
+- [x] Repository sync (metadata only)
+- [x] Analysis job queue and state machine
+- [x] Inngest/Worker analyzer (commit metadata extraction)
+- [x] Metrics computation and persistence
+- [x] Minimal Vibe profile generation
+- [x] Basic report UI
-**Deliverable:**
+**Deliverable:** ✓
- One private repo analyzed end-to-end
-- One Bolokono profile rendered with:
+- One Vibe profile rendered with:
- At least 5 computed metrics
- Build category timeline
- - One assigned Bolokono type with evidence
+ - One assigned Vibe persona with evidence
**Exit criteria:**
@@ -222,7 +228,7 @@ vibed-coding/
│
├── supabase/
│ ├── migrations/ # SQL migrations
-│ ├── functions/ # Edge Functions (optional)
+│ ├── functions/ # Edge Functions (legacy, see inngest-integration.md)
│ └── config.toml
│
└── docs/
@@ -1372,91 +1378,91 @@ Each task depends on the previous.
**Output:** Monorepo structure with apps and packages.
-#### Task 0.2: Supabase Setup
+#### Task 0.2: Supabase Setup ✓
- [x] Create Supabase project (production)
- [x] Set up local development with Supabase CLI
-- [ ] Create initial migration with full schema
-- [ ] Implement RLS policies
-- [ ] Create `claim_analysis_job` function
-- [ ] Test RLS policies with different user contexts
+- [x] Create initial migration with full schema
+- [x] Implement RLS policies
+- [x] Create `claim_analysis_job` function
+- [x] Test RLS policies with different user contexts
**Output:** Database with schema, RLS, and job claiming function.
-#### Task 0.3: Authentication
+#### Task 0.3: Authentication ✓
-- [ ] Configure GitHub OAuth provider in Supabase
-- [ ] Create GitHub OAuth app (for additional scopes)
-- [ ] Implement Supabase Auth in `apps/web`
-- [ ] Create sign-in page
-- [ ] Create auth callback handler
-- [ ] Store GitHub token in `github_accounts` (encrypted)
-- [ ] Create protected route middleware
+- [x] Configure GitHub OAuth provider in Supabase
+- [x] Create GitHub OAuth app (for additional scopes)
+- [x] Implement Supabase Auth in `apps/web`
+- [x] Create sign-in page
+- [x] Create auth callback handler
+- [x] Store GitHub token in `github_accounts` (encrypted)
+- [x] Create protected route middleware
**Output:** User can sign in with GitHub, token stored securely.
-#### Task 0.4: Repository Sync
+#### Task 0.4: Repository Sync ✓
-- [ ] Create GitHub API client in `apps/web`
-- [ ] Implement `POST /api/github/sync-repos` endpoint
-- [ ] Create repo selection UI
-- [ ] Implement repo connection flow (`user_repos`)
-- [ ] Implement repo disconnection with data cleanup
+- [x] Create GitHub API client in `apps/web`
+- [x] Implement `POST /api/github/sync-repos` endpoint
+- [x] Create repo selection UI
+- [x] Implement repo connection flow (`user_repos`)
+- [x] Implement repo disconnection with data cleanup
**Output:** User can see their repos and connect/disconnect them.
-#### Task 0.5: Analysis Job System
+#### Task 0.5: Analysis Job System ✓
-- [ ] Create `POST /api/analysis/start` endpoint
-- [ ] Set up Supabase Realtime subscription for job status
-- [ ] Create job status UI component with live updates
-- [ ] Implement basic worker loop in `apps/worker`
-- [ ] Test job claiming with `FOR UPDATE SKIP LOCKED`
+- [x] Create `POST /api/analysis/start` endpoint
+- [x] Set up Supabase Realtime subscription for job status
+- [x] Create job status UI component with live updates
+- [x] Implement Inngest-based job processing (primary) and worker fallback
+- [x] Test job claiming with `FOR UPDATE SKIP LOCKED`
**Output:** Jobs can be queued and status tracked in real-time.
-#### Task 0.6: Commit Analysis (Worker)
+#### Task 0.6: Commit Analysis (Worker) ✓
-- [ ] Implement GitHub API client in `apps/worker`
-- [ ] Implement commit fetching (paginated, batched)
-- [ ] Implement commit classification (`packages/core`)
-- [ ] Implement metrics computation (`packages/core`)
-- [ ] Store metrics in `analysis_metrics`
-- [ ] Handle rate limits gracefully
-- [ ] Handle large repos (time-distributed sampling + notice)
+- [x] Implement GitHub API client in `apps/worker`
+- [x] Implement commit fetching (paginated, batched)
+- [x] Implement commit classification (`packages/core`)
+- [x] Implement metrics computation (`packages/core`)
+- [x] Store metrics in `analysis_metrics`
+- [x] Handle rate limits gracefully
+- [x] Handle large repos (time-distributed sampling + notice)
**Output:** Worker fetches commits and computes metrics.
-#### Task 0.7: Report Generation (Worker)
+#### Task 0.7: Report Generation (Worker) ✓
-- [ ] Implement Bolokono type matching (`packages/core`)
-- [ ] Create Claude API client in `apps/worker`
-- [ ] Implement narrative generation with structured output
-- [ ] Implement narrative validation (banned phrases, SHA checks)
-- [ ] Store reports in `analysis_reports`
-- [ ] Handle generation failures gracefully
+- [x] Implement Vibe persona matching (`packages/core`)
+- [x] Create multi-provider LLM client (Anthropic, OpenAI, Gemini)
+- [x] Implement narrative generation with structured output
+- [x] Implement narrative validation (banned phrases, SHA checks)
+- [x] Store reports in `analysis_reports`
+- [x] Handle generation failures gracefully with fallback narratives
**Output:** Worker generates and stores reports.
-#### Task 0.8: Report UI
+#### Task 0.8: Report UI ✓
-- [ ] Create report page layout in `apps/web`
-- [ ] Implement Bolokono type display with badge
-- [ ] Implement metrics cards (key stats)
-- [ ] Implement narrative sections with evidence
-- [ ] Create build timeline visualization
-- [ ] Handle loading/error/insufficient-data states
+- [x] Create report page layout in `apps/web`
+- [x] Implement Vibe persona display with badge
+- [x] Implement metrics cards (key stats)
+- [x] Implement narrative sections with evidence
+- [x] Create build timeline visualization
+- [x] Handle loading/error/insufficient-data states
-**Output:** User can view their Bolokono profile.
+**Output:** User can view their Vibe profile.
-### Phase 0 Exit Criteria
+### Phase 0 Exit Criteria ✓
-- [ ] End-to-end flow works for private repo
-- [ ] All RLS policies enforced
-- [ ] Worker processes jobs correctly
-- [ ] Analysis completes in < 60s for < 1000 commits
-- [ ] Report displays type, metrics, and narrative
-- [ ] User can disconnect repo and data is deleted
+- [x] End-to-end flow works for private repo
+- [x] All RLS policies enforced
+- [x] Worker processes jobs correctly (via Inngest + fallback)
+- [x] Analysis completes in < 60s for < 1000 commits
+- [x] Report displays persona, metrics, and narrative
+- [x] User can disconnect repo and data is deleted
---
diff --git a/docs/WorkflowJournal.md b/docs/WorkflowJournal.md
index 66d611d..36f42a4 100644
--- a/docs/WorkflowJournal.md
+++ b/docs/WorkflowJournal.md
@@ -74,11 +74,13 @@ Format:
### 2025-01-16 - [DECISION] Edge Functions vs External Worker
**Context:** Need to run analysis jobs
-**Action:** Chose Supabase Edge Functions for Phase 0-1, with option to move to external worker for Phase 2+
+**Action:** Initially chose Supabase Edge Functions for Phase 0-1, with option to move to external worker for Phase 2+
**Time spent:** N/A (part of PRD)
**Automation opportunity:** None
**Notes:** Edge Functions have 60s timeout. Fine for < 1000 commits. Will need worker for large repos.
+**UPDATE (2026-01):** Migrated to **Inngest** as primary job processor with standalone worker as fallback. Inngest provides better observability, automatic retries, and serverless scaling. See `docs/architecture/inngest-integration.md`.
+
---
### 2025-01-16 - [INSIGHT] Workflow templates should be portable
diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md
index 6950d42..6818a11 100644
--- a/docs/architecture/overview.md
+++ b/docs/architecture/overview.md
@@ -2,9 +2,14 @@
This document explains how the Vibed Coding stack fits together, how data flows from a logged-in user through Supabase, the worker, and the UI, and which pieces of the codebase (web, worker, packages) own each responsibility. The diagrams use Mermaid syntax so you can paste them into any renderer, but the textual explanations also narrate every interaction.
+> **Related Documentation:**
+> - [How Vibed Works](../how-vibed-works.md) — Product-friendly explanation
+> - [Vibed Analysis Pipeline](./vibed-analysis-pipeline.md) — Detailed analysis algorithms and data flow
+> - [Inngest Integration](./inngest-integration.md) — Background job processing
+
## High-level Components
-1. **Next.js 16 (App Router) Web App** (`apps/web`)
+1. **Next.js 14+ (App Router) Web App** (`apps/web`)
- Hosts the public marketing homepage (`/`) plus authenticated areas (`/repos`, `/analysis/[jobId]`, `/login`, `/auth/callback`, etc.).
- Handles Supabase Auth via `proxy.ts`, guarding protected routes and synchronizing auth cookies.
- Calls Supabase Route Handlers (`/api/analysis/*`, `/api/github/sync-repos`, etc.) to start jobs, list repos, fetch shared insights, export share cards, and run other backend flows.
diff --git a/docs/architecture/vibed-analysis-pipeline.md b/docs/architecture/vibed-analysis-pipeline.md
new file mode 100644
index 0000000..c3a696d
--- /dev/null
+++ b/docs/architecture/vibed-analysis-pipeline.md
@@ -0,0 +1,852 @@
+# Vibed Analysis Pipeline — Technical Architecture
+
+> **Last Updated:** January 2026
+> **Maintainer:** Update this document when analysis logic, data models, or algorithms change.
+
+This document provides a comprehensive technical reference for how Vibed Coding analyzes repositories and generates user profiles. It covers data flow, algorithms, type definitions, and links to source code.
+
+---
+
+## Table of Contents
+
+1. [High-Level Architecture](#high-level-architecture)
+2. [Data Flow](#data-flow)
+3. [Repository Analysis Pipeline](#repository-analysis-pipeline)
+4. [Metrics Computation](#metrics-computation)
+5. [Vibe Axes System](#vibe-axes-system)
+6. [Persona Detection](#persona-detection)
+7. [Insights Generation](#insights-generation)
+8. [LLM Narrative Generation](#llm-narrative-generation)
+9. [Profile Aggregation](#profile-aggregation)
+10. [Database Schema](#database-schema)
+11. [Source Code References](#source-code-references)
+
+---
+
+## High-Level Architecture
+
+```mermaid
+flowchart TB
+ subgraph Client["Web Client (Next.js)"]
+ UI[Analysis UI]
+ API[API Routes]
+ end
+
+ subgraph Processing["Job Processing"]
+ Inngest[Inngest Function]
+ Worker[Fallback Worker]
+ end
+
+ subgraph External["External Services"]
+ GitHub[GitHub API]
+ LLM[LLM Provider]
+ end
+
+ subgraph Storage["Supabase"]
+ DB[(PostgreSQL)]
+ Auth[Supabase Auth]
+ end
+
+ subgraph Core["@vibed/core"]
+ Metrics[Metrics Computation]
+ Axes[Vibe Axes]
+ Persona[Persona Detection]
+ Insights[Insights Generation]
+ end
+
+ UI --> API
+ API --> DB
+ API --> Inngest
+ Inngest --> GitHub
+ Inngest --> Core
+ Inngest --> LLM
+ Inngest --> DB
+ Worker --> GitHub
+ Worker --> Core
+ Worker --> LLM
+ Worker --> DB
+```
+
+### Components
+
+| Component | Location | Responsibility |
+|-----------|----------|----------------|
+| Web Client | `apps/web` | UI, API routes, job triggering |
+| Inngest Function | `apps/web/src/inngest/functions/analyze-repo.ts` | Primary job processor |
+| Fallback Worker | `apps/worker/src/index.ts` | Self-hosted fallback |
+| @vibed/core | `packages/core/src/` | All analysis logic |
+| Database | `supabase/migrations/` | Persistent storage |
+
+---
+
+## Data Flow
+
+```mermaid
+sequenceDiagram
+ participant User
+ participant API as API Route
+ participant DB as Supabase
+ participant Inngest
+ participant GitHub
+ participant Core as @vibed/core
+ participant LLM
+
+ User->>API: POST /api/analysis/start
+ API->>DB: Create analysis_job (status=queued)
+ API->>Inngest: Fire repo/analyze.requested event
+ API-->>User: Return job_id
+
+ Inngest->>DB: Claim job (status=running)
+ Inngest->>GitHub: Fetch commits (paginated)
+ Inngest->>GitHub: Fetch PRs (if available)
+
+ Inngest->>Core: filterAutomationCommits()
+ Inngest->>Core: computeAnalysisMetrics()
+ Inngest->>Core: computeAnalysisInsights()
+ Inngest->>Core: computeVibeFromCommits()
+ Inngest->>Core: detectVibePersona()
+
+ Inngest->>DB: Store analysis_metrics
+ Inngest->>DB: Store analysis_insights
+ Inngest->>DB: Store vibe_insights
+
+ opt LLM Available
+ Inngest->>LLM: Generate narrative
+ Inngest->>DB: Store analysis_reports
+ end
+
+ Inngest->>Core: aggregateUserProfile()
+ Inngest->>DB: Update user_profiles
+ Inngest->>DB: Update job (status=done)
+
+ User->>API: GET /api/analysis/:id
+ API->>DB: Fetch results
+ API-->>User: Return analysis data
+```
+
+---
+
+## Repository Analysis Pipeline
+
+### Step 1: Job Creation
+
+```typescript
+// API creates job record
+interface AnalysisJob {
+ id: string;
+ user_id: string;
+ repo_id: string;
+ status: "queued" | "running" | "done" | "error";
+ created_at: string;
+ started_at: string | null;
+ completed_at: string | null;
+ error_message: string | null;
+}
+```
+
+### Step 2: Commit Fetching
+
+```mermaid
+flowchart LR
+ A[Get Repo Metadata] --> B{Repo Age}
+ B -->|< 1 year| C[Fetch Recent 300]
+ B -->|> 1 year| D[Time-Distributed Sampling]
+ D --> E[Split into 6-24 buckets]
+ E --> F[Sample evenly per bucket]
+ C --> G[Commit List]
+ F --> G
+ G --> H[Fetch Details per Commit]
+ H --> I[CommitEvent Array]
+```
+
+**Sampling Strategy:**
+- Repos are divided into time buckets (6-24 based on size)
+- Each bucket is sampled evenly to capture patterns across the repo's lifetime
+- Maximum 300 commits per analysis
+- Commit details (file paths, stats) fetched in parallel batches
+
+### Step 3: Automation Filtering
+
+```typescript
+// packages/core/src/index.ts
+function isAutomationCommit(event: CommitEvent): boolean {
+ // Filters: dependabot, renovate, release-please, github-actions, etc.
+ // Based on email patterns and commit message patterns
+}
+
+function filterAutomationCommits(events: CommitEvent[]): CommitEvent[]
+```
+
+**Filtered Patterns:**
+- Bot emails: `dependabot`, `renovate`, `github-actions`, `[bot]`
+- Message patterns: `chore(release):`, `bump version`, `[automated]`
+
+---
+
+## Metrics Computation
+
+### Input Type
+
+```typescript
+interface CommitEvent {
+ sha: string;
+ message: string;
+ author_date: string;
+ committer_date: string;
+ author_email: string;
+ files_changed: number;
+ additions: number;
+ deletions: number;
+ parents: string[];
+ file_paths?: string[]; // For subsystem detection
+}
+```
+
+### Output Type
+
+```typescript
+interface AnalysisMetrics {
+ // Volume
+ total_commits: number;
+ total_additions: number;
+ total_deletions: number;
+ total_files_changed: number;
+
+ // Timing
+ first_commit_date: string;
+ last_commit_date: string;
+ active_days: number;
+ span_days: number;
+
+ // Commit Size Distribution
+ commit_size_p50: number;
+ commit_size_p90: number;
+ commit_size_mean: number;
+ commit_size_stddev: number;
+
+ // Frequency
+ commits_per_active_day_mean: number;
+ commits_per_active_day_max: number;
+
+ // Rhythm
+ hours_between_commits_p50: number;
+ hours_between_commits_p90: number;
+ burstiness_score: number; // -1 (steady) to +1 (bursty)
+
+ // Message Analysis
+ message_length_p50: number;
+ message_length_p90: number;
+ conventional_commit_ratio: number;
+
+ // Iteration Patterns
+ fix_commit_ratio: number;
+ fixup_sequence_count: number; // fix-after-feature sequences
+
+ // Build Sequence
+ category_first_occurrence: Record;
+ category_distribution: Record;
+
+ // Merge Behavior
+ merge_commit_ratio: number;
+
+ // Confidence
+ data_quality_score: number; // 0-100
+}
+```
+
+### Build Category Classification
+
+```typescript
+type BuildCategory =
+ | "setup" | "auth" | "feature" | "test" | "infra"
+ | "docs" | "refactor" | "fix" | "style" | "chore" | "unknown";
+
+function classifyCommit(message: string): BuildCategory {
+ // Priority 1: Conventional commit prefixes (feat:, fix:, test:, etc.)
+ // Priority 2: Scope overrides (auth, setup)
+ // Priority 3: Keyword matching
+ // Priority 4: Default to "feature" for substantive commits
+}
+```
+
+### Burstiness Score Algorithm
+
+```typescript
+function calculateBurstiness(timestamps: Date[]): number {
+ // Burstiness = (stddev - mean) / (stddev + mean)
+ // Range: -1 (perfectly regular) to +1 (highly bursty)
+ const intervals = timestamps.map((t, i) =>
+ i > 0 ? (t - timestamps[i-1]) / (1000 * 60 * 60) : 0
+ ).slice(1);
+
+ const mean = avg(intervals);
+ const stddev = std(intervals);
+ return (stddev - mean) / (stddev + mean);
+}
+```
+
+---
+
+## Vibe Axes System
+
+Six deterministic axes scored 0-100:
+
+```mermaid
+graph TD
+ subgraph Axes["Six Vibe Axes"]
+ A["A: Automation Heaviness"]
+ B["B: Guardrail Strength"]
+ C["C: Iteration Loop Intensity"]
+ D["D: Planning Signal"]
+ E["E: Surface Area per Change"]
+ F["F: Shipping Rhythm"]
+ end
+
+ subgraph Inputs["Input Signals"]
+ I1[Commit Size Stats]
+ I2[PR Chunkiness]
+ I3[First-Touch Percentiles]
+ I4[Category Distribution]
+ I5[Fix Sequences]
+ I6[Conventional Commits]
+ I7[Issue Linking]
+ I8[Episode Subsystems]
+ I9[Burstiness Score]
+ end
+
+ I1 --> A
+ I2 --> A
+ I3 --> B
+ I4 --> B
+ I4 --> C
+ I5 --> C
+ I6 --> D
+ I7 --> D
+ I8 --> E
+ I9 --> F
+```
+
+### Axis Computation
+
+```typescript
+interface AxisValue {
+ score: number; // 0-100
+ level: "low" | "medium" | "high";
+ why: string[]; // Evidence IDs
+}
+
+interface VibeAxes {
+ automation_heaviness: AxisValue;
+ guardrail_strength: AxisValue;
+ iteration_loop_intensity: AxisValue;
+ planning_signal: AxisValue;
+ surface_area_per_change: AxisValue;
+ shipping_rhythm: AxisValue;
+}
+```
+
+### Axis A: Automation Heaviness
+
+**Signals:**
+- Average files changed per commit
+- p90 commit size (additions + deletions)
+- p90 PR changed files
+
+**Formula:**
+```
+Score = 0.5 × scoreFromZ(avgFiles, mid=4, spread=4)
+ + 0.3 × scoreFromZ(p90Commit, mid=400, spread=400)
+ + 0.2 × scoreFromZ(prP90, mid=25, spread=25)
+```
+
+### Axis B: Guardrail Strength
+
+**Signals:**
+- First-touch percentile for tests/CI/docs (earlier = stronger)
+- Guardrail commit density (tests + docs + chore + CI)
+- PR checklist presence rate
+
+**Formula:**
+```
+Score = 0.5 × (1 - avgFirstTouch) × 100
+ + 0.3 × guardrailDensity × 200
+ + 0.2 × prChecklistRate × 100
+```
+
+### Axis C: Iteration Loop Intensity
+
+**Signals:**
+- Fix-after-feature sequence count
+- Fix commit ratio
+- Episode fix density
+
+**Formula:**
+```
+Score = 0.5 × scoreFromZ(fixSeq/total, mid=0.12, spread=0.12)
+ + 0.3 × fixRatio × 100
+ + 0.2 × episodeFixDensity × 100
+```
+
+### Axis D: Planning Signal
+
+**Signals:**
+- Conventional commit ratio
+- PR issue linking rate
+- Docs-before-feature pattern
+
+**Formula:**
+```
+Score = 0.35 × issueLinkRate × 100
+ + 0.35 × conventionalRatio × 100
+ + 0.30 × docsFirst × 100
+```
+
+### Axis E: Surface Area per Change
+
+**Signals:**
+- Median subsystems touched per work episode
+
+**Formula:**
+```
+Score = scoreFromZ(medianSubsystems, mid=3, spread=2)
+```
+
+### Axis F: Shipping Rhythm
+
+**Signals:**
+- Burstiness score
+- p90 commits per episode
+
+**Formula:**
+```
+Score = 0.6 × ((burstiness + 1) / 2) × 100
+ + 0.4 × scoreFromZ(episodeP90, mid=6, spread=6)
+```
+
+---
+
+## Persona Detection
+
+```mermaid
+flowchart TD
+ Axes[Six Axis Scores] --> Rules[Persona Rules]
+ Rules --> Strict{Strict Match?}
+ Strict -->|Yes| StrictPersona[Matched Persona]
+ Strict -->|No| Loose{Loose Match?}
+ Loose -->|≥50% conditions, score≥60| LoosePersona[Nearest Persona]
+ Loose -->|No| Fallback[Balanced Builder]
+
+ StrictPersona --> Output[VibePersona]
+ LoosePersona --> Output
+ Fallback --> Output
+```
+
+### Persona Rules
+
+```typescript
+type VibePersonaId =
+ | "prompt_sprinter" // Vibe Prototyper
+ | "guardrailed_viber" // Test-First Validator
+ | "spec_first_director" // Spec-Driven Architect
+ | "vertical_slice_shipper" // Agent Orchestrator
+ | "fix_loop_hacker" // Hands-On Debugger
+ | "rapid_risk_taker" // Rapid Risk-Taker
+ | "balanced_builder"; // Reflective Balancer (fallback)
+```
+
+| Persona | Conditions |
+|---------|------------|
+| **Vibe Prototyper** | A≥70, C≥65, B<40, D<45 |
+| **Test-First Validator** | A≥65, B≥65, C≥40 |
+| **Spec-Driven Architect** | D≥70, B≥55, A≥40 |
+| **Agent Orchestrator** | E≥70, A≥60 |
+| **Hands-On Debugger** | C≥80, F≥60 |
+| **Rapid Risk-Taker** | A≥65, B<45, D<50, F≥40 |
+| **Balanced Builder** | Fallback when no rules match |
+
+### Confidence Calculation
+
+```typescript
+function getConfidence(meta: { commitCount, prCount, dataQualityScore }): Confidence {
+ const commitOk = meta.commitCount >= 200;
+ const prOk = meta.prCount >= 15;
+ const qualityOk = meta.dataQualityScore >= 70;
+
+ if ((commitOk || prOk) && qualityOk && personaScore >= 75) return "high";
+ if ((meta.commitCount >= 80 || meta.prCount >= 6) && personaScore >= 65) return "medium";
+ return "low";
+}
+```
+
+---
+
+## Insights Generation
+
+### AnalysisInsights Structure
+
+```typescript
+interface AnalysisInsights {
+ version: string;
+ timezone: "UTC";
+ generated_at: string;
+
+ totals: { commits: number };
+
+ streak: {
+ longest_days: number;
+ start_day: string | null;
+ end_day: string | null;
+ confidence: Confidence;
+ evidence_shas: string[];
+ };
+
+ timing: {
+ top_weekdays: Array<{ weekday: number; count: number }>;
+ peak_weekday: number | null;
+ peak_hour: number | null;
+ peak_window: "mornings" | "afternoons" | "evenings" | "late_nights" | null;
+ confidence: Confidence;
+ evidence_shas: string[];
+ };
+
+ commits: {
+ top_category: BuildCategory | null;
+ category_counts: Record;
+ features: number;
+ fixes: number;
+ features_per_fix: number | null;
+ confidence: Confidence;
+ evidence_shas: string[];
+ };
+
+ chunkiness: {
+ avg_files_changed: number | null;
+ label: "slicer" | "mixer" | "chunker" | null;
+ confidence: Confidence;
+ evidence_shas: string[];
+ };
+
+ multi_agent_signals: {
+ co_author_count: number;
+ ai_trailer_count: number;
+ ai_keyword_count: number;
+ pr_squash_merge_rate: number | null;
+ pr_template_rate: number | null;
+ pr_checklist_rate: number | null;
+ pr_linked_issue_rate: number | null;
+ confidence: Confidence;
+ evidence_shas: string[];
+ };
+
+ artifact_traceability: ArtifactTraceability;
+
+ persona: AnalysisInsightPersona;
+ share_template: AnalysisInsightShareTemplate;
+ persona_delta: AnalysisInsightPersonaDelta[];
+ tech_signals: AnalysisInsightTechSignals;
+
+ sources: string[];
+ disclaimers: string[];
+}
+```
+
+### Chunkiness Classification
+
+```typescript
+function classifyChunkiness(avgFilesChanged: number): "slicer" | "mixer" | "chunker" {
+ if (avgFilesChanged <= 3) return "slicer"; // Focused changes
+ if (avgFilesChanged <= 8) return "mixer"; // Balanced
+ return "chunker"; // Wide scope
+}
+```
+
+### Multi-Agent Signal Detection
+
+```mermaid
+flowchart LR
+ Commits[Commit Messages] --> Trailers[Parse Trailers]
+ Trailers --> CoAuthor[Co-authored-by Count]
+ Trailers --> AITrailer[AI Trailer Count]
+
+ Messages[Message Keywords] --> AIKeywords[Agent/Copilot/Claude mentions]
+
+ PRs[Pull Requests] --> SquashRate[Squash Merge Rate]
+ PRs --> TemplateRate[Template Usage Rate]
+ PRs --> ChecklistRate[Checklist Rate]
+ PRs --> IssueRate[Issue Link Rate]
+
+ CoAuthor --> Signals[Multi-Agent Signals]
+ AITrailer --> Signals
+ AIKeywords --> Signals
+ SquashRate --> Signals
+ TemplateRate --> Signals
+ ChecklistRate --> Signals
+ IssueRate --> Signals
+```
+
+---
+
+## LLM Narrative Generation
+
+### When LLM Is Used
+
+```mermaid
+flowchart TD
+ Start[Analysis Complete] --> Check{LLM Available?}
+ Check -->|No| Fallback[Metrics-Only Narrative]
+ Check -->|Yes| Resolve[Resolve LLM Config]
+
+ Resolve --> UserKey{User API Key?}
+ UserKey -->|Yes| UseUser[Use User Key]
+ UserKey -->|No| FreeTier{Free Tier Available?}
+ FreeTier -->|Yes| UsePlatform[Use Platform Key]
+ FreeTier -->|No| Fallback
+
+ UseUser --> Generate[Generate Narrative]
+ UsePlatform --> Generate
+ Generate --> Store[Store in analysis_reports]
+```
+
+### LLM Input (Privacy-Safe)
+
+The LLM receives:
+- Metrics JSON (no commit content)
+- Insights JSON (persona, timing, patterns)
+- Episode summary (timestamps, categories, sizes)
+- Commit lines: `timestamp sha category size files` (NO message content)
+
+**Never sent to LLM:**
+- Commit message text
+- File contents
+- Project/product names
+- Business domain information
+
+### Supported Providers
+
+| Provider | Models | Config |
+|----------|--------|--------|
+| Anthropic | claude-sonnet-4, claude-haiku | `ANTHROPIC_API_KEY` |
+| OpenAI | gpt-4o, gpt-4o-mini | `OPENAI_API_KEY` |
+| Google | gemini-2.0-flash, gemini-1.5-flash | `GEMINI_API_KEY` |
+
+---
+
+## Profile Aggregation
+
+### Multi-Repo to Single Profile
+
+```mermaid
+flowchart TD
+ subgraph Repos["Individual Repo Analyses"]
+ R1[Repo A: 500 commits]
+ R2[Repo B: 200 commits]
+ R3[Repo C: 100 commits]
+ end
+
+ subgraph Aggregation["Aggregation Logic"]
+ W[Weight by Commit Count]
+ M[Merge Metrics]
+ A[Average Axes]
+ P[Re-detect Persona]
+ end
+
+ subgraph Profile["User Profile"]
+ UP[Aggregated Profile]
+ N[Profile Narrative]
+ end
+
+ R1 --> W
+ R2 --> W
+ R3 --> W
+ W --> M
+ M --> A
+ A --> P
+ P --> UP
+ UP --> N
+```
+
+### Aggregation Algorithm
+
+```typescript
+function aggregateUserProfile(repoInsights: RepoInsightSummary[]): UserProfile {
+ // 1. Calculate total commits for weighting
+ const totalCommits = sum(repoInsights.map(r => r.commit_count));
+
+ // 2. Weight each repo's contribution
+ const weights = repoInsights.map(r => r.commit_count / totalCommits);
+
+ // 3. Aggregate metrics (weighted average)
+ const aggregatedMetrics = weightedAverage(repoInsights, weights);
+
+ // 4. Aggregate axes (weighted average)
+ const aggregatedAxes = weightedAverageAxes(repoInsights, weights);
+
+ // 5. Re-detect persona from aggregated axes
+ const persona = detectVibePersona(aggregatedAxes, {
+ commitCount: totalCommits,
+ prCount: sum(repoInsights.map(r => r.pr_count)),
+ });
+
+ // 6. Generate profile narrative (if LLM available)
+ const narrative = generateProfileNarrative(aggregatedMetrics, persona);
+
+ return { metrics: aggregatedMetrics, axes: aggregatedAxes, persona, narrative };
+}
+```
+
+### Profile Confidence
+
+| Repos Analyzed | Confidence |
+|----------------|------------|
+| 1 repo | Low — snapshot only |
+| 2-3 repos | Medium — patterns emerging |
+| 4+ repos | High — consistent patterns |
+
+---
+
+## Database Schema
+
+### Core Tables
+
+```mermaid
+erDiagram
+ users ||--o{ repos : owns
+ users ||--o{ analysis_jobs : requests
+ users ||--|| user_profiles : has
+ repos ||--o{ analysis_jobs : analyzed_by
+ analysis_jobs ||--|| analysis_metrics : produces
+ analysis_jobs ||--|| analysis_insights : produces
+ analysis_jobs ||--|| analysis_reports : produces
+ analysis_jobs ||--|| vibe_insights : produces
+ repos ||--o{ pull_requests : has
+
+ users {
+ uuid id PK
+ string email
+ timestamp created_at
+ }
+
+ repos {
+ uuid id PK
+ uuid user_id FK
+ string full_name
+ boolean is_private
+ timestamp last_analyzed_at
+ }
+
+ analysis_jobs {
+ uuid id PK
+ uuid user_id FK
+ uuid repo_id FK
+ string status
+ timestamp created_at
+ timestamp completed_at
+ }
+
+ analysis_metrics {
+ uuid id PK
+ uuid job_id FK
+ jsonb metrics_json
+ }
+
+ analysis_insights {
+ uuid id PK
+ uuid job_id FK
+ jsonb insights_json
+ }
+
+ vibe_insights {
+ uuid id PK
+ uuid job_id FK
+ jsonb axes
+ jsonb persona
+ jsonb cards
+ jsonb evidence_index
+ }
+
+ analysis_reports {
+ uuid id PK
+ uuid job_id FK
+ string vibe_type
+ string confidence
+ jsonb narrative
+ }
+
+ user_profiles {
+ uuid id PK
+ uuid user_id FK
+ jsonb aggregated_metrics
+ jsonb aggregated_axes
+ jsonb persona
+ jsonb narrative
+ int repos_analyzed
+ }
+
+ pull_requests {
+ uuid id PK
+ uuid repo_id FK
+ int github_pr_number
+ string title
+ boolean merged
+ string merge_method
+ timestamp created_at
+ }
+```
+
+---
+
+## Source Code References
+
+| Component | File | Key Functions |
+|-----------|------|---------------|
+| Metrics Computation | `packages/core/src/index.ts` | `computeAnalysisMetrics()` |
+| Commit Classification | `packages/core/src/index.ts` | `classifyCommit()`, `isAutomationCommit()` |
+| Insights Generation | `packages/core/src/index.ts` | `computeAnalysisInsights()` |
+| Vibe Axes | `packages/core/src/vibe.ts` | `computeVibeAxes()` |
+| Persona Detection | `packages/core/src/vibe.ts` | `detectVibePersona()` |
+| Episode Building | `packages/core/src/vibe.ts` | `buildWorkEpisodes()` |
+| Subsystem Classification | `packages/core/src/vibe.ts` | `classifySubsystem()` |
+| LLM Client | `packages/core/src/llm/` | `createLLMClient()` |
+| Profile Aggregation | `packages/core/src/index.ts` | `aggregateUserProfile()` |
+| Inngest Function | `apps/web/src/inngest/functions/analyze-repo.ts` | Main job processor |
+| Fallback Worker | `apps/worker/src/index.ts` | Self-hosted processor |
+
+---
+
+## Related Documentation
+
+- [How Vibed Works (Product Overview)](../how-vibed-works.md)
+- [Vibe Metrics v2](./vibe-metrics-v2.md) — Original axis design
+- [Inngest Integration](./inngest-integration.md) — Job processing details
+- [Architecture Overview](./overview.md) — System components
+- [PRD: Multi-Agent Detection](../prd/multi-agent-detection.md) — AI workflow signals
+
+---
+
+## Attribution
+
+This architecture builds on concepts and research from the developer tooling community:
+
+| Concept | Source |
+|---------|--------|
+| "Vibe coding" term | [Andrej Karpathy](https://x.com/karpathy/status/1886192184808149383) (Feb 2025) |
+| Orchestrator vs Conductor patterns | [Addy Osmani](https://addyosmani.com/blog/future-agentic-coding/) |
+| Code analytics methodologies | [GitClear](https://www.gitclear.com/) |
+| Co-author attribution patterns | [GitHub Copilot Docs](https://docs.github.com/en/copilot) |
+
+See [internal research docs](../research/) for persona taxonomy synthesis.
+
+---
+
+## Assumptions & Caveats
+
+1. **GitHub API Only:** Analysis is limited to what GitHub exposes (no IDE telemetry)
+2. **Commit Sampling:** Large repos are sampled; not all commits analyzed
+3. **Bot Filtering:** Heuristic-based; some edge cases may slip through
+4. **Persona Rules:** Deterministic rules may not capture all workflow styles
+5. **LLM Privacy:** Commit content never sent; only metadata and statistics
+6. **Aggregation Weights:** Larger repos have more influence on profile
+
+---
+
+*This document should be updated whenever analysis logic, data models, or algorithms change.*
diff --git a/docs/github-setup.md b/docs/github-setup.md
index 2bba8db..c7fc5f8 100644
--- a/docs/github-setup.md
+++ b/docs/github-setup.md
@@ -16,7 +16,7 @@ This document summarizes what you need to do before you can authenticate via Git
This project relies on Supabase Auth using GitHub OAuth (see `docs/PRD.md`).
1. Start your local Supabase stack if it is not running: `npm run supabase:start`.
-2. Open Supabase Studio at `http://127.0.0.1:54423` and navigate to **Authentication → Providers → GitHub**.
+2. Open Supabase Studio at `http://127.0.0.1:54323` and navigate to **Authentication → Providers → GitHub**.
3. Paste the Client ID and Client Secret from the OAuth app you created above.
4. Select scopes required for private repo access (at least `repo` and `read:user`).
diff --git a/docs/how-vibed-works.md b/docs/how-vibed-works.md
new file mode 100644
index 0000000..046292a
--- /dev/null
+++ b/docs/how-vibed-works.md
@@ -0,0 +1,187 @@
+# How Vibed Coding Works
+
+> **Last Updated:** January 2026
+> **Maintainer:** Update this document when analysis logic, personas, or metrics change.
+
+Vibed Coding analyzes your git history to reveal your coding style and patterns. Think of it as "Spotify Wrapped for vibe coders." We look at *how* you build, not *what* you build.
+
+---
+
+## The Big Picture
+
+```
+Your Git History → Analysis → Vibe Profile
+ ↓ ↓ ↓
+ Commits Metrics Persona + Insights
+ PRs Axes Narrative
+ Timing Scores Share Cards
+```
+
+**Key Principle:** Vibed is *observational, not judgmental*. We detect patterns, not quality. Every coding style has strengths.
+
+---
+
+## What We Analyze
+
+### Data Sources (All from GitHub API)
+
+| Source | What We Extract | Privacy Note |
+|--------|-----------------|--------------|
+| **Commits** | Timestamps, file counts, additions/deletions, message structure | We never store or analyze code content |
+| **Pull Requests** | Merge methods, checklists, issue links, templates | Body text parsed for structure only |
+| **File Paths** | Subsystem classification (ui, api, tests, etc.) | Paths only, no file contents |
+
+### What We Don't Access
+- Source code contents
+- Private comments or discussions
+- IDE activity or local history
+- Unpushed commits
+
+---
+
+## The Analysis Pipeline
+
+### Step 1: Fetch Commits
+We retrieve up to 300 commits from your repository via GitHub API, sampling evenly across the repo's lifetime to capture patterns from start to present.
+
+### Step 2: Filter Automation
+Bot commits (dependabot, renovate, release-please, etc.) are automatically filtered out so your analysis reflects *your* work, not automation.
+
+### Step 3: Compute Metrics
+We calculate 25+ metrics across several dimensions:
+
+**Volume & Timing**
+- Total commits, additions, deletions
+- Active days vs span days
+- Commit frequency patterns
+
+**Rhythm & Burstiness**
+- Hours between commits (median, p90)
+- Burstiness score (-1 = steady, +1 = bursty)
+- Peak coding hours and days
+
+**Commit Patterns**
+- Size distribution (p50, p90)
+- Conventional commit ratio
+- Fix-after-feature sequences
+
+**Build Categories**
+- Classification: feature, fix, test, docs, infra, refactor, etc.
+- Category distribution and first-occurrence order
+
+### Step 4: Compute Vibe Axes
+Six deterministic axes (0-100 scores) capture your workflow style:
+
+| Axis | What It Measures |
+|------|------------------|
+| **Automation Heaviness** | How "agentic" your workflow looks: large commits, chunky PRs |
+| **Guardrail Strength** | How much you stabilize with tests, CI, docs early |
+| **Iteration Loop Intensity** | How often you do rapid fix cycles |
+| **Planning Signal** | Structured commits, issue linking, docs-first patterns |
+| **Surface Area per Change** | How many subsystems you touch per work session |
+| **Shipping Rhythm** | Bursty vs steady shipping patterns |
+
+### Step 5: Detect Persona
+Based on your axes, we match you to one of 7 Vibe Personas:
+
+| Persona | Signature Pattern |
+|---------|-------------------|
+| **Vibe Prototyper** | High automation, rapid iteration, minimal guardrails |
+| **Test-First Validator** | Strong guardrails with automation |
+| **Spec-Driven Architect** | High planning signal, early guardrails |
+| **Agent Orchestrator** | Wide surface area, high automation |
+| **Hands-On Debugger** | Intense fix loops, fast shipping |
+| **Rapid Risk-Taker** | High automation, low guardrails, fast shipping |
+| **Reflective Balancer** | Balanced across all axes (fallback) |
+
+### Step 6: Generate Insights
+Deterministic insights are computed server-side:
+
+- **Longest Streak:** Consecutive days with commits
+- **Peak Window:** When you code most (mornings, afternoons, evenings, late nights)
+- **Chunkiness:** Slicer (focused), Mixer (balanced), or Chunker (wide scope)
+- **Tech Signals:** Keywords detected in commit messages
+- **Multi-Agent Signals:** Co-author trailers, AI attribution patterns
+
+### Step 7: LLM Narrative (Optional)
+If LLM is configured, we generate a human-readable narrative about your *engineering patterns*, never about what you built, only how you built it.
+
+**Privacy:** The LLM only sees metadata (timestamps, categories, metrics), never commit message content or code.
+
+---
+
+## Profile Aggregation
+
+### Single Repo Analysis
+One repo gives you a snapshot of your coding style for that project.
+
+### Multi-Repo User Profile
+When you analyze multiple repos, Vibed aggregates them into a single **User Profile**:
+
+```
+Repo A Analysis ─┐
+Repo B Analysis ─┼─→ Aggregated User Profile
+Repo C Analysis ─┘
+```
+
+**Aggregation Logic:**
+- Metrics are weighted by commit count (larger repos contribute more)
+- Axes are averaged across repos
+- Persona is re-detected from aggregated axes
+- Confidence increases with more repos (3+ repos = stronger signal)
+
+---
+
+## Confidence Levels
+
+Every insight includes a confidence level:
+
+| Level | Meaning |
+|-------|---------|
+| **High** | 200+ commits or 15+ PRs, good data quality |
+| **Medium** | 80+ commits or 6+ PRs |
+| **Low** | Limited data, take insights with a grain of salt |
+
+---
+
+## What Vibed Is NOT
+
+- **Not a productivity tracker:** We don't measure "good" vs "bad"
+- **Not a code quality tool:** We don't analyze code, just patterns
+- **Not AI detection:** We detect workflow patterns, not AI usage
+- **Not surveillance:** You control what repos to analyze, data is yours
+
+---
+
+## Privacy Principles
+
+1. **No code access:** We only read metadata from GitHub API
+2. **No message content to LLM:** Commit messages are classified locally, never sent to AI
+3. **User-controlled:** You choose which repos to analyze
+4. **Deletable:** Disconnect a repo and all analysis data is removed
+
+---
+
+## Attribution
+
+Vibed Coding builds on research and concepts from the developer tooling community:
+
+- **"Vibe coding"**: Term coined by [Andrej Karpathy](https://x.com/karpathy/status/1886192184808149383) in February 2025, later named [Collins Dictionary Word of the Year 2025](https://en.wikipedia.org/wiki/Vibe_coding).
+- **Orchestrator vs Conductor patterns**: From [Addy Osmani's work on agentic coding](https://addyosmani.com/blog/future-agentic-coding/).
+- **Code analytics research**: Informed by [GitClear's developer productivity studies](https://www.gitclear.com/).
+- **Persona taxonomy**: Original synthesis drawing from academic TDD research, [GitHub Copilot documentation](https://docs.github.com/en/copilot), and developer workflow studies.
+
+Our internal research documents are available in [docs/research/](./research/).
+
+---
+
+## Related Documentation
+
+- [Technical Architecture](./architecture/vibed-analysis-pipeline.md): Deep dive with Mermaid diagrams
+- [Vibe Metrics v2](./architecture/vibe-metrics-v2.md): Axis computation details
+- [PRD: Vibed Narrative Layer](./PRD-vibed.md): Product requirements
+- [PRD: Profile Aggregation](./PRD-profile-aggregation.md): Multi-repo aggregation
+
+---
+
+*This document should be updated whenever analysis logic, personas, or metrics change.*
diff --git a/docs/implementation-trackers/vibed.md b/docs/implementation-trackers/vibed.md
index e3dd2a2..0504cbc 100644
--- a/docs/implementation-trackers/vibed.md
+++ b/docs/implementation-trackers/vibed.md
@@ -1,54 +1,64 @@
# Implementation Tracker: Vibed Narrative Layer
## Context
-This tracker accompanies `docs/PRD-vibed.md`. It captures the discrete implementation tasks needed to move Bolokono from a metrics-heavy analysis tool to the Vibed narrative experience, covering schema, worker, API, UI, and sharing layers.
+This tracker accompanies `docs/PRD-vibed.md`. It captures the discrete implementation tasks needed to move from a metrics-heavy analysis tool to the Vibed narrative experience, covering schema, worker, API, UI, and sharing layers.
## Tracker
### F1. Insights & Persona Schema
**Task:** Design `analysis_insights` (and related persona signals) to capture deterministic Vibed outputs.
**Deliverables:**
-- [ ] Schema defined (longest streak, weekday/time window, chunkiness, persona tag + confidence, tech signals, share template).
-- [ ] Migration file created for `analysis_insights`.
-- [ ] Story for persona evolution + deltas captured (per-job history).
+- [x] Schema defined (longest streak, weekday/time window, chunkiness, persona tag + confidence, tech signals, share template).
+- [x] Migration file created for `analysis_insights` (`0005_add_analysis_insights.sql`, `0006_enrich_analysis_insights.sql`).
+- [x] Vibe insights table added (`0010_add_vibe_insights.sql`).
+- [x] Story for persona evolution + deltas captured (per-job history via `vibe_insights`).
**Blocks:** F2
### F2. Worker & Narrative Pipeline
**Task:** Extend the worker to compute `insights_json`, persist to `analysis_insights`, and feed narratives.
**Deliverables:**
-- [ ] Insight computation logic implemented + unit tested (streak, persona, chunkiness, tech signal detection).
-- [ ] `analysis_insights` row inserted per job with persona/confidence + evidence.
-- [ ] Updated Narrative LLM prompt referencing insights explicitly.
-- [ ] Share-card payload generation (colors/text template) included in worker output.
+- [x] Insight computation logic implemented + unit tested (streak, persona, chunkiness, tech signal detection) in `@vibed/core`.
+- [x] `vibe_insights` row inserted per job with persona/confidence + evidence via Inngest function.
+- [x] Updated Narrative LLM prompt referencing insights explicitly.
+- [x] Share-card payload generation (colors/text template) included in worker output.
**Depends on:** F1
**Blocks:** F3, F4
### F3. API + Supabase Access
**Task:** Expose insights/share data through REST endpoints and Supabase RLS.
**Deliverables:**
-- [ ] `GET /api/analysis/:jobId/insights` returns `analysis_insights` + key metrics.
-- [ ] `GET /api/analysis/:jobId/report` includes persona badge, confidence, and share template.
-- [ ] (Optional) `POST /api/analysis/:jobId/share` triggers share card export or return template data.
-- [ ] Supabase policies mirror `analysis_reports` access.
+- [x] API endpoints expose insights + key metrics (`/api/analysis/[id]/*`).
+- [x] Report includes persona badge, confidence, and share template.
+- [x] Supabase policies mirror `analysis_reports` access.
**Depends on:** F2
**Blocks:** F4
### F4. Vibed UX/UI + Share Experience
-**Task:** Build the new hero/data UI plus “Show me the data” deep dive and share cards.
+**Task:** Build the new hero/data UI plus "Show me the data" deep dive and share cards.
**Deliverables:**
-- [ ] Vibed highlights layer (streak, rhythms, chunkiness, persona archetype line, confidence text).
-- [ ] Share section offering PNG/SVG export plus copyable summary, reusing precomputed templates.
-- [ ] Persona timeline/history component showing persona evolution per job/repo.
-- [ ] Deep dive panel linking to raw metrics/narrative/evidence and persona signals.
-- [ ] Light theme/sticker aesthetic consistent with Vibed marketing.
+- [x] Vibed highlights layer (streak, rhythms, chunkiness, persona archetype line, confidence text).
+- [x] Persona timeline/history component showing persona evolution per job/repo.
+- [x] Deep dive panel linking to raw metrics/narrative/evidence and persona signals.
+- [ ] Share section offering PNG/SVG export plus copyable summary (partially implemented).
+- [ ] Light theme/sticker aesthetic consistent with Vibed marketing (ongoing polish).
**Depends on:** F3
### F5. Reflection & Testing
**Task:** Ensure deterministic insight generation, persona detection, and share assets behave as expected.
**Deliverables:**
-- [ ] Unit tests covering streak, persona classification outcomes, and chunkiness thresholds.
+- [x] Unit tests covering streak, persona classification outcomes, and chunkiness thresholds (31+ tests in `@vibed/core`).
- [ ] Visual regression or storybook story for share cards.
-- [ ] Documented confidence thresholds + persona hints for designers.
-- [ ] Workflow documentation updated (`docs/research` links, PRD updates).
+- [x] Documented confidence thresholds + persona hints in `vibe.ts`.
+- [x] Workflow documentation updated (`docs/research` links, PRD updates).
**Depends on:** F2, F4
+## Progress Summary
+
+| Phase | Status | Notes |
+|-------|--------|-------|
+| F1. Insights & Persona Schema | ✅ Complete | Multiple migrations applied |
+| F2. Worker & Narrative Pipeline | ✅ Complete | Inngest + fallback worker |
+| F3. API + Supabase Access | ✅ Complete | RLS policies in place |
+| F4. Vibed UX/UI + Share Experience | 🟡 Mostly Complete | Share export needs polish |
+| F5. Reflection & Testing | 🟡 Mostly Complete | Visual regression pending |
+
diff --git a/docs/prd/multi-agent-detection.md b/docs/prd/multi-agent-detection.md
index 6a2cdcf..a4e0c11 100644
--- a/docs/prd/multi-agent-detection.md
+++ b/docs/prd/multi-agent-detection.md
@@ -2,7 +2,7 @@
## Overview
-**Status:** Planning
+**Status:** Implemented (Phases 1-5 complete)
**Priority:** High
**Owner:** TBD
**Created:** January 2026
diff --git a/docs/research/ai-era-coding-personas.md b/docs/research/ai-era-coding-personas.md
index 243676b..7e9b16e 100644
--- a/docs/research/ai-era-coding-personas.md
+++ b/docs/research/ai-era-coding-personas.md
@@ -42,7 +42,16 @@ The UI is doing interpretation work. This holds short-term but should move to th
## Research Sources
-Primary sources include Addy Osmani’s AI workflows, Cursor 2.0 docs, GitClear 2024 research, academic TDD benchmarks (arxiv 2025), Axur Engineering, humanwhocodes.com persona guides, Cursor/Replit/Qodo tooling guides, GitHub Copilot materials, and developer persona frameworks.
+Primary sources:
+
+- [Addy Osmani: The Future of Agentic Coding](https://addyosmani.com/blog/future-agentic-coding/) — Orchestrator vs conductor patterns
+- [Andrej Karpathy's "Vibe Coding" tweet](https://x.com/karpathy/status/1886192184808149383) — Origin of the term (Feb 2025)
+- [GitClear 2024 Code Quality Report](https://www.gitclear.com/) — Code churn and developer productivity metrics
+- [GitHub Copilot Documentation](https://docs.github.com/en/copilot) — Co-author attribution, agent workflows
+- [Cursor Documentation](https://cursor.com/docs) — AI-assisted development patterns
+- [Vibe Coding Wikipedia](https://en.wikipedia.org/wiki/Vibe_coding) — Collins Dictionary Word of the Year 2025
+- Academic TDD benchmarks (arxiv 2025)
+- Developer persona frameworks from humanwhocodes.com
## Final Thought
From 7ec206fa56c9502029d49885d13363b29c3f869e Mon Sep 17 00:00:00 2001
From: Abou Kone
Date: Wed, 21 Jan 2026 12:45:33 -0500
Subject: [PATCH 2/5] docs: update terminology in landing page and
documentation
Update text to clarify "vibe coding" vs "AI Assisted Engineering" terminology
Make language more approachable for non-technical audiences
---
apps/web/src/app/page.tsx | 6 ++++++
docs/how-vibed-works.md | 4 +++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx
index 4aec475..c2885f8 100644
--- a/apps/web/src/app/page.tsx
+++ b/apps/web/src/app/page.tsx
@@ -779,6 +779,12 @@ function MarketingLanding() {
better. We surface signals from your commit history to shine a light on how you build
with AI. What feels like you, what feels new, and how your workflow is evolving.
+
+ The term “vibe coding” can be polarizing, but it captures the cultural moment around
+ AI-shaped development. We personally prefer “AI Assisted Engineering” because it’s
+ more explicit about the role of AI. This is a playful side project, so we keep it
+ light and approachable for non-technical folks.
+
diff --git a/docs/how-vibed-works.md b/docs/how-vibed-works.md
index 046292a..5f93ca3 100644
--- a/docs/how-vibed-works.md
+++ b/docs/how-vibed-works.md
@@ -3,7 +3,9 @@
> **Last Updated:** January 2026
> **Maintainer:** Update this document when analysis logic, personas, or metrics change.
-Vibed Coding analyzes your git history to reveal your coding style and patterns. Think of it as "Spotify Wrapped for vibe coders." We look at *how* you build, not *what* you build.
+Vibed Coding analyzes your git history to reveal your vibe coding/ AI Assited Engineering style and patterns. Think of it as "Spotify Wrapped for vibe coders." We look at *how* you build, not *what* you build.
+
+Note: The term "vibe coding" can be polarizing, but it captures the cultural moment around AI-shaped development. We personally prefer "AI Assisted Engineering" because it’s more explicit about the role of AI. This is a playful side project, so we lean into the pop framing and keep it approachable for non-technical folks.
---
From 411ba506074e2d35c5ec0c07aff8f824a86ef96b Mon Sep 17 00:00:00 2001
From: Abou Kone
Date: Wed, 21 Jan 2026 16:37:38 -0500
Subject: [PATCH 3/5] feat: enhance profile sharing and versioning features
- Introduced ProfileShareSection and ProfileVersionSelector components for improved user experience in sharing profiles.
- Updated user profile schema to include narrative and LLM model information.
- Enhanced admin job management to track profile updates and personas.
- Added share functionality for profiles, including metrics and insights display.
- Documented LLM narrative workflow and share experience improvements for better clarity and usability.
---
apps/web/src/app/admin/actions.ts | 46 +-
apps/web/src/app/admin/jobs/page.tsx | 15 +
.../app/analysis/[jobId]/AnalysisClient.tsx | 775 ++++--------------
apps/web/src/app/page.tsx | 188 ++++-
.../src/components/ProfileVersionSelector.tsx | 165 ++++
.../components/share/ProfileShareSection.tsx | 133 +++
.../web/src/components/share/ShareActions.tsx | 291 +++++++
apps/web/src/components/share/ShareCard.tsx | 93 +++
apps/web/src/components/share/index.ts | 18 +
apps/web/src/components/share/share-image.ts | 242 ++++++
apps/web/src/components/share/types.ts | 83 ++
docs/architecture/llm-narrative-workflow.md | 391 +++++++++
docs/prd/share-experience-improvements.md | 617 ++++++++++++++
packages/db/src/database.types.ts | 21 +
14 files changed, 2405 insertions(+), 673 deletions(-)
create mode 100644 apps/web/src/components/ProfileVersionSelector.tsx
create mode 100644 apps/web/src/components/share/ProfileShareSection.tsx
create mode 100644 apps/web/src/components/share/ShareActions.tsx
create mode 100644 apps/web/src/components/share/ShareCard.tsx
create mode 100644 apps/web/src/components/share/index.ts
create mode 100644 apps/web/src/components/share/share-image.ts
create mode 100644 apps/web/src/components/share/types.ts
create mode 100644 docs/architecture/llm-narrative-workflow.md
create mode 100644 docs/prd/share-experience-improvements.md
diff --git a/apps/web/src/app/admin/actions.ts b/apps/web/src/app/admin/actions.ts
index b79a164..458fe39 100644
--- a/apps/web/src/app/admin/actions.ts
+++ b/apps/web/src/app/admin/actions.ts
@@ -521,6 +521,8 @@ export async function getAllJobs(
commit_count: number | null;
created_at: string;
completed_at: string | null;
+ profile_updated: boolean;
+ profile_persona: string | null;
}>;
total: number;
}> {
@@ -576,27 +578,49 @@ export async function getAllJobs(
// Get user and repo names
const userIds = [...new Set((jobs ?? []).map((j) => j.user_id))];
const repoIds = [...new Set((jobs ?? []).map((j) => j.repo_id).filter(Boolean))];
+ const jobIds = (jobs ?? []).map((j) => j.id);
- const [{ data: users }, { data: repos }] = await Promise.all([
+ const [{ data: users }, { data: repos }, { data: profileHistory }] = await Promise.all([
adminSupabase.from("users").select("id, github_username").in("id", userIds),
adminSupabase.from("repos").select("id, full_name").in("id", repoIds),
+ // Get profile history entries triggered by these jobs
+ adminSupabase
+ .from("user_profile_history")
+ .select("trigger_job_id, profile_snapshot")
+ .in("trigger_job_id", jobIds),
]);
const usernameById = new Map((users ?? []).map((u) => [u.id, u.github_username]));
const repoNameById = new Map((repos ?? []).map((r) => [r.id, r.full_name]));
+ // Map job ID to profile update info
+ const profileUpdateByJobId = new Map();
+ for (const ph of profileHistory ?? []) {
+ if (ph.trigger_job_id) {
+ const snapshot = ph.profile_snapshot as { persona?: { name?: string } } | null;
+ profileUpdateByJobId.set(ph.trigger_job_id, {
+ persona: snapshot?.persona?.name ?? null,
+ });
+ }
+ }
+
return {
success: true,
- jobs: (jobs ?? []).map((j) => ({
- id: j.id,
- user_id: j.user_id,
- username: usernameById.get(j.user_id) ?? null,
- repo_name: repoNameById.get(j.repo_id ?? "") ?? null,
- status: j.status,
- commit_count: j.commit_count,
- created_at: j.created_at,
- completed_at: j.completed_at,
- })),
+ jobs: (jobs ?? []).map((j) => {
+ const profileUpdate = profileUpdateByJobId.get(j.id);
+ return {
+ id: j.id,
+ user_id: j.user_id,
+ username: usernameById.get(j.user_id) ?? null,
+ repo_name: repoNameById.get(j.repo_id ?? "") ?? null,
+ status: j.status,
+ commit_count: j.commit_count,
+ created_at: j.created_at,
+ completed_at: j.completed_at,
+ profile_updated: Boolean(profileUpdate),
+ profile_persona: profileUpdate?.persona ?? null,
+ };
+ }),
total: totalCount ?? 0,
};
}
diff --git a/apps/web/src/app/admin/jobs/page.tsx b/apps/web/src/app/admin/jobs/page.tsx
index 3a28461..d4042a2 100644
--- a/apps/web/src/app/admin/jobs/page.tsx
+++ b/apps/web/src/app/admin/jobs/page.tsx
@@ -88,6 +88,7 @@ export default async function AdminJobsPage({
Repo
Status
Commits
+
Profile
Created
Completed
@@ -112,6 +113,20 @@ export default async function AdminJobsPage({
- ) : null}
-
{history.length > 1 ? (
diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx
index c2885f8..43523ca 100644
--- a/apps/web/src/app/page.tsx
+++ b/apps/web/src/app/page.tsx
@@ -3,6 +3,8 @@ import { createSupabaseServerClient } from "@/lib/supabase/server";
import type { Database } from "@vibed/db";
import { wrappedTheme } from "@/lib/theme";
import { formatMatchedRule, AXIS_LEGEND } from "@/lib/format-labels";
+import { ProfileShareSection } from "@/components/share";
+import { ProfileVersionSelector } from "@/components/ProfileVersionSelector";
import { createClient } from "@supabase/supabase-js";
import {
aggregateUserProfile,
@@ -14,17 +16,43 @@ import {
} from "@vibed/core";
const heroFeatures = [
- "A Vibed profile built from vibe-coding signals in your commit history",
+ "A Vibed profile built from AI-assisted engineering signals in your commit history",
"Persona snapshots that evolve as you add more repos",
- "Share-ready cards with playful language and honest confidence",
+ "Share-ready cards that highlight your vibe coding patterns",
"Deep dive metrics and evidence when you want receipts",
];
const timeline = [
- { title: "Connect GitHub", description: "Sign in, then pick the repos that feel like you." },
- { title: "Run a vibe check", description: "We read commit metadata and patterns (not your code)." },
- { title: "Get your Vibed read", description: "Highlights, categories, and insights into how you build." },
- { title: "See your persona", description: "A playful archetype that changes as your work evolves." },
+ {
+ title: "Fetch commit metadata",
+ description:
+ "We sample up to 300 commits across your repo's lifetime (timestamps, sizes, file paths). No code content.",
+ },
+ {
+ title: "Filter automation noise",
+ description:
+ "Bots like Dependabot or release workflows are filtered out so the signal reflects your work.",
+ },
+ {
+ title: "Compute metrics + axes",
+ description:
+ "25+ metrics roll up into six Vibe Axes (planning, guardrails, rhythm, surface area, and more).",
+ },
+ {
+ title: "Detect persona + insights",
+ description:
+ "We map your axes to a persona and generate streaks, timing, and workflow highlights.",
+ },
+ {
+ title: "Optional LLM narrative",
+ description:
+ "If you opt in, we summarize patterns using metadata only—never code or message content.",
+ },
+ {
+ title: "Aggregate your profile",
+ description:
+ "Multiple repos roll into a single Vibed profile, weighted by commit volume.",
+ },
];
type AuthStats = {
@@ -49,6 +77,7 @@ type AuthStats = {
generatedAt: string | null;
};
userProfile?: {
+ personaId: string;
personaName: string;
personaTagline: string | null;
personaConfidence: string;
@@ -62,6 +91,13 @@ type AuthStats = {
commitCount: number;
}>;
updatedAt: string | null;
+ narrative?: {
+ headline?: string;
+ paragraphs?: string[];
+ highlights?: string[];
+ } | null;
+ llmModel?: string | null;
+ llmKeySource?: string | null;
};
};
@@ -437,7 +473,7 @@ export default async function Home({
supabase
.from("user_profiles")
.select(
- "persona_name, persona_tagline, persona_confidence, total_repos, total_commits, axes_json, repo_personas_json, updated_at, job_ids"
+ "persona_id, persona_name, persona_tagline, persona_confidence, total_repos, total_commits, axes_json, repo_personas_json, updated_at, job_ids, narrative_json, llm_model, llm_key_source"
)
.eq("user_id", user.id)
.maybeSingle(),
@@ -452,6 +488,7 @@ export default async function Home({
}>;
const maybeProfileData = userProfileResult.data as {
+ persona_id: string;
persona_name: string;
persona_tagline: string | null;
persona_confidence: string;
@@ -466,6 +503,13 @@ export default async function Home({
}>;
updated_at: string | null;
job_ids: unknown;
+ narrative_json: {
+ headline?: string;
+ paragraphs?: string[];
+ highlights?: string[];
+ } | null;
+ llm_model: string | null;
+ llm_key_source: string | null;
} | null;
const profileJobIds = Array.isArray(maybeProfileData?.job_ids)
@@ -531,13 +575,14 @@ export default async function Home({
? await supabase
.from("user_profiles")
.select(
- "persona_name, persona_tagline, persona_confidence, total_repos, total_commits, axes_json, repo_personas_json, updated_at"
+ "persona_id, persona_name, persona_tagline, persona_confidence, total_repos, total_commits, axes_json, repo_personas_json, updated_at, narrative_json, llm_model, llm_key_source"
)
.eq("user_id", user.id)
.maybeSingle()
: null;
const userProfileData = (profileIsStale ? refreshedProfileResult?.data ?? null : maybeProfileData) as {
+ persona_id: string;
persona_name: string;
persona_tagline: string | null;
persona_confidence: string;
@@ -551,6 +596,13 @@ export default async function Home({
commitCount: number;
}>;
updated_at: string | null;
+ narrative_json: {
+ headline?: string;
+ paragraphs?: string[];
+ highlights?: string[];
+ } | null;
+ llm_model: string | null;
+ llm_key_source: string | null;
} | null;
const recentDoneJobIds = recentDoneJobs.map((job) => job.id);
@@ -643,6 +695,7 @@ export default async function Home({
: undefined,
userProfile: userProfileData
? {
+ personaId: userProfileData.persona_id,
personaName: userProfileData.persona_name,
personaTagline: userProfileData.persona_tagline,
personaConfidence: userProfileData.persona_confidence,
@@ -651,6 +704,9 @@ export default async function Home({
axes: userProfileData.axes_json ?? {},
repoPersonas: userProfileData.repo_personas_json ?? [],
updatedAt: userProfileData.updated_at ?? null,
+ narrative: userProfileData.narrative_json ?? null,
+ llmModel: userProfileData.llm_model ?? null,
+ llmKeySource: userProfileData.llm_key_source ?? null,
}
: undefined,
};
@@ -743,7 +799,7 @@ function MarketingLanding() {
{
title: "Spec-Driven Architect",
description:
- "Plans thoroughly before touching code; constraints show up early and often.",
+ "Plans thoroughly before shipping changes; constraints show up early and often.",
},
{
title: "Test-First Validator",
@@ -771,13 +827,16 @@ function MarketingLanding() {
For vibe coders
- Find your Vibed coding profile{" "}
+
+ Find your Vibed AI-assisted engineering profile
+ {" "}
and the personality behind your workflow
- Vibed is a playful experiment by vibe coders who want to understand themselves
- better. We surface signals from your commit history to shine a light on how you build
- with AI. What feels like you, what feels new, and how your workflow is evolving.
+ Vibed is a playful experiment by vibe coders who want to understand their AI-assisted
+ engineering patterns. We surface signals from your commit history to shine a light on
+ how you build with AI, what feels like you, what feels new, and how your workflow is
+ evolving.
The term “vibe coding” can be polarizing, but it captures the cultural moment around
@@ -852,7 +911,7 @@ function MarketingLanding() {
Persona previews
You may see one of these (or another persona). These are lenses on your
- vibe-coding style. Observations, not labels.
+ AI-assisted engineering (vibe-coding) style. Observations, not labels.
;
- const cards = [
- {
- label: "Reads captured",
- value: stats.completedJobs,
- helper: "Every run adds a chapter.",
- },
- {
- label: "Vibe shifts",
- value: shiftValue,
- helper: shiftHelper,
- },
- {
- label: "Most frequent vibe",
- value: dominantPersona ?? "Still forming",
- helper:
- recentLabels.length === 0
- ? "Complete a vibe check to see your read."
- : `Based on your last ${recentLabels.length} reads.`,
- },
- ];
-
function generateCrossRepoInsight(): string {
if (!stats.userProfile) return "Add more repos to unlock cross-repo insights.";
const repos = stats.userProfile.repoPersonas ?? [];
@@ -1056,9 +1094,51 @@ function AuthenticatedDashboard({
return `Your ${stats.userProfile.personaName.toLowerCase()} profile emerges from ${repos.length} repos and ${stats.userProfile.totalCommits.toLocaleString()} commits.`;
}
+ // Compute top axes for share card
+ const topAxes = stats.userProfile
+ ? Object.entries(stats.userProfile.axes)
+ .map(([key, val]) => ({
+ name: axisMeta[key as keyof typeof axisMeta]?.name ?? key,
+ score: val.score,
+ }))
+ .sort((a, b) => b.score - a.score)
+ .slice(0, 4)
+ : [];
+
+ // Use LLM narrative if available, otherwise fall back to deterministic insight
+ const narrativeFromLLM = stats.userProfile?.narrative;
+ const crossRepoInsight = narrativeFromLLM?.headline
+ ? narrativeFromLLM.headline
+ : generateCrossRepoInsight();
+
+ // Full narrative paragraphs (for expanded display)
+ const narrativeParagraphs = narrativeFromLLM?.paragraphs ?? [];
+ const narrativeHighlights = narrativeFromLLM?.highlights ?? [];
+ const hasLLMNarrative = Boolean(narrativeFromLLM?.headline || narrativeParagraphs.length > 0);
+
return (
-
+
+ {/* HERO: Share Card - The main action for users with a profile */}
+ {stats.userProfile ? (
+
+ ) : null}
+
+ {/* Profile History - Version selector */}
+ {stats.userProfile ? (
+
+ ) : null}
+
{/* Unified Profile Card */}
- Your Vibed profile is now using a non-LLM narrative because you've exceeded the
+ Your Unified VCP is now using a non-LLM narrative because you've exceeded the
free limit of {pendingProfileMeta.repoLimit} repos. Add your own API key in Settings
to restore LLM-generated profiles.
- Each vibed repo reveals your coding persona, confidence level, and the evidence behind it.
+ Each Repo VCP reveals your coding persona, confidence level, and the evidence behind it.
diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx
index 794343b..de0eb18 100644
--- a/apps/web/src/app/layout.tsx
+++ b/apps/web/src/app/layout.tsx
@@ -21,24 +21,24 @@ const geistMono = Geist_Mono({
const appUrl = process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:8108";
export const metadata: Metadata = {
- title: "Vibed Coding · Your AI coding profile",
+ title: "Vibe Coding Profile · Your AI coding profile",
description:
- "Turn your commit history into a Vibed Coding Persona — patterns, insights, and shareable profiles grounded in commit evidence.",
+ "Turn your commit history into a Vibe Coding Profile (VCP) — patterns, insights, and shareable profiles grounded in commit evidence.",
metadataBase: new URL(appUrl),
openGraph: {
- title: "Vibed Coding · Your AI coding profile",
+ title: "Vibe Coding Profile · Your AI coding profile",
description:
- "A shareable Vibed Coding Persona from your commit history — patterns and insights grounded in evidence.",
+ "A shareable Vibe Coding Profile (VCP) from your commit history — patterns and insights grounded in evidence.",
url: appUrl,
locale: "en_US",
type: "website",
- siteName: "Vibed Coding",
+ siteName: "Vibe Coding Profile",
},
twitter: {
card: "summary_large_image",
- title: "Vibed Coding · Your AI coding profile",
+ title: "Vibe Coding Profile · Your AI coding profile",
description:
- "A shareable Vibed Coding Persona from your commit history — patterns and insights grounded in evidence.",
+ "A shareable Vibe Coding Profile (VCP) from your commit history — patterns and insights grounded in evidence.",
},
};
diff --git a/apps/web/src/app/login/page.tsx b/apps/web/src/app/login/page.tsx
index f39b206..cbe9fc0 100644
--- a/apps/web/src/app/login/page.tsx
+++ b/apps/web/src/app/login/page.tsx
@@ -7,7 +7,7 @@ export default function LoginPage() {
- Vibed Coding
+ Vibe Coding Profile
Sign in to analyze your build patterns from git history.
diff --git a/apps/web/src/app/methodology/page.tsx b/apps/web/src/app/methodology/page.tsx
index 01a1635..888cd68 100644
--- a/apps/web/src/app/methodology/page.tsx
+++ b/apps/web/src/app/methodology/page.tsx
@@ -14,7 +14,7 @@ export default async function MethodologyPage() {
How we compute your persona
- Vibed infers your Vibe Coding persona by spotting AI-assisted engineering patterns in the
+ Vibe Coding Profile infers your Vibe Coding persona by spotting AI-assisted engineering patterns in the
Git history of repos you connect.
diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx
index 43523ca..ba4d1e5 100644
--- a/apps/web/src/app/page.tsx
+++ b/apps/web/src/app/page.tsx
@@ -16,7 +16,7 @@ import {
} from "@vibed/core";
const heroFeatures = [
- "A Vibed profile built from AI-assisted engineering signals in your commit history",
+ "A Vibe Coding Profile (VCP) built from AI-assisted engineering signals in your commit history",
"Persona snapshots that evolve as you add more repos",
"Share-ready cards that highlight your vibe coding patterns",
"Deep dive metrics and evidence when you want receipts",
@@ -49,9 +49,14 @@ const timeline = [
"If you opt in, we summarize patterns using metadata only—never code or message content.",
},
{
- title: "Aggregate your profile",
+ title: "Create Repo VCP",
description:
- "Multiple repos roll into a single Vibed profile, weighted by commit volume.",
+ "Each repo gets its own Repo VCP—a snapshot of your vibe coding style for that project.",
+ },
+ {
+ title: "Aggregate into Unified VCP",
+ description:
+ "Multiple Repo VCPs roll into your Unified VCP, weighted by commit volume across all repos.",
},
];
@@ -828,13 +833,12 @@ function MarketingLanding() {
- Find your Vibed AI-assisted engineering profile
+ Find your Vibe Coding Profile (VCP)
{" "}
and the personality behind your workflow
- Vibed is a playful experiment by vibe coders who want to understand their AI-assisted
- engineering patterns. We surface signals from your commit history to shine a light on
+ A Vibe Coding Profile (VCP) is your AI-assisted engineering persona—revealed through patterns in your commit history. We surface signals from your git history to shine a light on
how you build with AI, what feels like you, what feels new, and how your workflow is
evolving.
@@ -937,7 +941,7 @@ function MarketingLanding() {
@@ -1147,7 +1151,7 @@ function AuthenticatedDashboard({
- Vibed Coding connects to GitHub, fetches commit history, computes metrics, and stores the
+ Vibe Coding Profile connects to GitHub, fetches commit history, computes metrics, and stores the
results in Supabase Postgres. Access to rows is scoped to your authenticated account
via Supabase Row Level Security (RLS) policies for user-facing reads.
@@ -66,7 +66,7 @@ export default function SecurityPage() {
Note: when fetching commit details from GitHub, the API response can include file
- paths and diff snippets. Vibed Coding’s current worker extracts and stores counts/stats
+ paths and diff snippets. Vibe Coding Profile’s current worker extracts and stores counts/stats
(like number of files and additions/deletions), not file contents.
@@ -88,7 +88,7 @@ export default function SecurityPage() {
Recommendations
- Vibed Coding is designed for personal insight. Keep the blast radius small.
+ Vibe Coding Profile is designed for personal insight. Keep the blast radius small.