Skip to content

Commit e45e55e

Browse files
devakoneclaude
andcommitted
feat: rewrite vibe coding language to be AI-native
Update persona taglines, axis descriptions, insight card subtitles, share card metrics, and LLM narrative prompts to target AI-assisted coding workflows instead of generic software engineering patterns. - Persona taglines now reference prompting, agents, and vibe coding - Axis descriptions explain AI tool usage patterns - "Strongest" metric shows "AI-Heavy Automation" instead of "Automation 78" - "Peak Varied" renamed to "All Hours" - LLM prompts rewritten to focus on AI-assisted workflow analysis - Fallback narratives updated with AI-native section titles Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ea1943e commit e45e55e

7 files changed

Lines changed: 104 additions & 91 deletions

File tree

apps/web/src/app/api/share/[format]/[userId]/route.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,29 +105,37 @@ export async function GET(
105105
strongest: "N/A",
106106
style: "Balanced",
107107
rhythm: "Mixed",
108-
peak: "Varied"
108+
peak: "All Hours"
109109
};
110110

111111
if (axes) {
112112
// 1. Strongest
113113
let maxScore = -1;
114-
let maxName = "";
114+
let maxKey = "";
115115
const AXIS_NAMES: Record<string, string> = {
116116
automation_heaviness: "Automation",
117117
guardrail_strength: "Guardrails",
118-
iteration_loop_intensity: "Loops",
118+
iteration_loop_intensity: "Iteration",
119119
planning_signal: "Planning",
120-
surface_area_per_change: "Scope",
120+
surface_area_per_change: "Surface Area",
121121
shipping_rhythm: "Rhythm",
122122
};
123+
const AXIS_HIGH_LABELS: Record<string, string> = {
124+
automation_heaviness: "AI-Heavy",
125+
guardrail_strength: "Rigorous",
126+
iteration_loop_intensity: "Rapid",
127+
planning_signal: "Structured",
128+
surface_area_per_change: "Wide",
129+
shipping_rhythm: "Bursty",
130+
};
123131
for (const [key, val] of Object.entries(axes)) {
124132
const axis = val as { score: number };
125133
if (axis.score > maxScore && AXIS_NAMES[key]) {
126134
maxScore = axis.score;
127-
maxName = AXIS_NAMES[key];
135+
maxKey = key;
128136
}
129137
}
130-
const strongest = maxName ? `${maxName} ${maxScore}` : "N/A";
138+
const strongest = maxKey ? `${AXIS_HIGH_LABELS[maxKey]} ${AXIS_NAMES[maxKey]}` : "N/A";
131139

132140
// 2. Style
133141
let style = "Mixed"; // Default

apps/web/src/components/vcp/constants.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,54 +23,54 @@ export const AXIS_METADATA: Record<AxisKey, AxisMetadata> = {
2323
automation_heaviness: {
2424
name: "Automation",
2525
shortName: "Auto",
26-
description: "How much you leverage AI/automation for large-scale changes",
26+
description: "How much you rely on AI agents and tools for generating code",
2727
longDescription:
28-
'How "agentic" your workflow looks, driven by large commits and chunky PRs. Higher scores indicate more automation-heavy changes.',
28+
"How much of your output comes from AI-assisted generation versus manual edits. Higher scores indicate more agent-driven, multi-file changes.",
2929
lowLabel: "Manual",
3030
highLabel: "AI-Heavy",
3131
},
3232
guardrail_strength: {
3333
name: "Guardrails",
3434
shortName: "Guard",
35-
description: "How early and consistently tests/CI/docs appear in your workflow",
35+
description: "How closely tests, CI, and docs follow your AI-generated changes",
3636
longDescription:
37-
"How much you stabilize work with tests, CI, and docs early in the lifecycle. Higher scores mean guardrails appear sooner and more consistently.",
37+
"How quickly guardrails appear after AI-generated code lands. Higher scores mean tests, CI, and docs show up alongside or right after the AI output.",
3838
lowLabel: "Light",
3939
highLabel: "Rigorous",
4040
},
4141
iteration_loop_intensity: {
4242
name: "Iteration",
4343
shortName: "Iter",
44-
description: "How quickly you cycle through fix-forward loops after changes",
44+
description: "How often you run prompt-fix-run loops to refine AI output",
4545
longDescription:
46-
'How often you run rapid "generate → run → fix → run" cycles. Higher scores mean faster, denser iteration loops.',
46+
'How often you cycle through "prompt → run → fix → run" loops after AI-generated changes. Higher scores mean faster, denser iteration.',
4747
lowLabel: "Stable",
4848
highLabel: "Rapid",
4949
},
5050
planning_signal: {
5151
name: "Planning",
5252
shortName: "Plan",
53-
description: "How much upfront structure (issues, specs, docs-first) appears",
53+
description: "How much structure you define before prompting AI to generate code",
5454
longDescription:
55-
"How much intent and structure appear up front: linked issues, structured commits, and docs-first patterns. Higher scores indicate more planning.",
55+
"How much upfront structure shapes your AI workflow: specs, linked issues, and docs-first patterns. Higher scores mean prompts follow plans, not the other way around.",
5656
lowLabel: "Emergent",
5757
highLabel: "Structured",
5858
},
5959
surface_area_per_change: {
6060
name: "Surface Area",
6161
shortName: "Scope",
62-
description: "How many subsystems your typical change touches",
62+
description: "How many parts of the codebase your typical prompt or change touches",
6363
longDescription:
64-
"How broad each unit of work is across subsystems. Higher scores mean typical changes span more areas of the codebase.",
64+
"How broad each unit of work is across the codebase. Higher scores mean your prompts and changes span multiple subsystems at once.",
6565
lowLabel: "Narrow",
6666
highLabel: "Wide",
6767
},
6868
shipping_rhythm: {
6969
name: "Rhythm",
7070
shortName: "Rhythm",
71-
description: "Your shipping pattern — steady vs bursty",
71+
description: "Your coding session pattern — steady output vs intense vibe sessions",
7272
longDescription:
73-
"Bursty versus steady shipping over time. Higher scores indicate bursty sessions with gaps; lower scores indicate a steadier cadence.",
73+
"How your coding sessions are distributed over time. Higher scores indicate intense vibe coding sessions followed by quiet stretches; lower scores indicate a steadier cadence.",
7474
lowLabel: "Steady",
7575
highLabel: "Bursty",
7676
},

apps/web/src/inngest/functions/analyze-repo.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ export function toNarrativeFallback(params: {
6565
summary: `Analyzed ${metrics.total_commits} commits over ${metrics.active_days} active days.`,
6666
sections: [
6767
{
68-
title: "Build rhythm",
69-
content: `Median gap between commits: ${metrics.hours_between_commits_p50.toFixed(1)}h. Burstiness score: ${metrics.burstiness_score.toFixed(2)}.`,
68+
title: "Coding session rhythm",
69+
content: `Median gap between commits: ${metrics.hours_between_commits_p50.toFixed(1)}h. Session intensity (burstiness): ${metrics.burstiness_score.toFixed(2)}.`,
7070
evidence: events.slice(0, 5).map((e) => e.sha),
7171
},
7272
{
73-
title: "Iteration",
74-
content: `Fix ratio: ${(metrics.fix_commit_ratio * 100).toFixed(0)}%. Fix-after-feature sequences: ${metrics.fixup_sequence_count}.`,
73+
title: "Fix-forward loops",
74+
content: `Fix ratio: ${(metrics.fix_commit_ratio * 100).toFixed(0)}%. Prompt-fix-run sequences: ${metrics.fixup_sequence_count}.`,
7575
evidence: events.slice(0, 5).map((e) => e.sha),
7676
},
7777
],
@@ -210,7 +210,8 @@ export async function generateNarrativeWithLLM(params: {
210210
})();
211211

212212
const systemPrompt = [
213-
"You write a narrative report about SOFTWARE ENGINEERING PATTERNS observed in commit history.",
213+
"You write a narrative report about AI-ASSISTED CODING PATTERNS observed in commit history.",
214+
"This profile measures how a developer works with AI coding tools (Claude, Copilot, Cursor, etc.).",
214215
"",
215216
"PRIVACY RULES (CRITICAL - VIOLATION MEANS FAILURE):",
216217
"- NEVER mention the project name, product name, app name, or repository name in your output",
@@ -221,22 +222,23 @@ export async function generateNarrativeWithLLM(params: {
221222
"- NEVER describe WHAT is being built - only describe HOW development happens",
222223
"",
223224
"ALLOWED TOPICS (your output must ONLY cover these):",
224-
"- Development rhythm: commit frequency, timing patterns, burst vs steady patterns",
225-
"- Iteration style: big batches vs small increments, refactoring frequency",
226-
"- Code organization: how changes are structured, file churn patterns",
227-
"- Testing approach: when tests appear relative to features, test coverage patterns",
228-
"- Documentation patterns: when docs are written, documentation frequency",
229-
"- Collaboration signals: merge patterns, review cycles (if visible)",
225+
"- Session rhythm: vibe coding session patterns, timing, burst vs steady cadence",
226+
"- AI-assisted workflow: agentic vs manual phases, large AI-generated drops vs incremental edits",
227+
"- Prompt-iterate loops: fix-forward cycles, prompt-fix-run patterns after AI output",
228+
"- Guardrail timing: when tests/CI/docs appear relative to AI-generated code",
229+
"- Scope patterns: single-file vs full-stack changes, breadth of AI-assisted edits",
230+
"- Planning signals: specs-first vs emergent architecture, structure before prompting",
230231
"",
231-
"SECTION TITLES must be generic engineering terms like:",
232-
"- 'Development Rhythm', 'Iteration Patterns', 'Code Organization', 'Testing Approach'",
232+
"SECTION TITLES must be AI-workflow terms like:",
233+
"- 'Session Rhythm', 'AI-Assisted Workflow', 'Fix-Forward Loops', 'Guardrail Timing'",
233234
"NOT product-specific like 'Admin Portal Development' or 'Feature Implementation'",
234235
"",
235236
"CONTENT RULES:",
236237
"- Never infer intent, skill, or code quality. Avoid speculation and motivational language.",
237238
"- Every claim must cite at least one specific metric name and value (e.g. burstiness_score=0.42).",
238239
"- Each section must include evidence: 2-6 commit SHAs that support the section.",
239-
"- Provide a concise tagline (<=60 characters) that describes the developer's vibe. This will be displayed on the share card and must remain observational.",
240+
"- Provide a concise tagline (<=60 characters) that describes the developer's vibe coding style. This will be displayed on the share card and must remain observational.",
241+
"- Use vocabulary like: vibe coding, prompt-iterate, agentic, AI-assisted, fix loops, session rhythm",
240242
"",
241243
"Output must be STRICT JSON with this schema:",
242244
'{"summary":"...","tagline":"...","sections":[{"title":"...","content":"...","evidence":["sha", "..."]}],"highlights":[{"metric":"...","value":"...","interpretation":"..."}]}',
@@ -295,7 +297,7 @@ export async function generateNarrativeWithLLM(params: {
295297
"Commit lines (oldest→newest, compact):",
296298
...commitLines,
297299
"",
298-
"Produce a concise narrative about the SOFTWARE ENGINEERING PATTERNS observed: development phases, iteration loops, stabilization patterns, testing rhythm. Do NOT describe what was built - only HOW it was built from an engineering perspective. Prefer 4-6 sections.",
300+
"Produce a concise narrative about the AI-ASSISTED CODING PATTERNS observed: prompt-iterate loops, agentic vs manual phases, session rhythm, guardrail timing, and scope of changes. Do NOT describe what was built - only HOW it was built and how AI tools shaped the workflow. Prefer 4-6 sections.",
299301
].join("\n");
300302

301303
// Use the LLM abstraction layer

apps/web/src/lib/profile-narrative.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -75,20 +75,20 @@ export function toProfileNarrativeFallback(params: {
7575
.join(", ");
7676

7777
return {
78-
summary: `Across ${totalRepos} repositories and ${totalCommits} commits, you demonstrate a ${persona.name} coding style with ${persona.confidence} confidence.`,
78+
summary: `Across ${totalRepos} repositories and ${totalCommits} commits, your AI-assisted coding workflow maps to the ${persona.name} persona with ${persona.confidence} confidence.`,
7979
sections: [
8080
{
81-
title: "Your Coding Identity",
82-
content: `Your aggregated profile shows you as a ${persona.name}. ${persona.tagline}. This pattern emerges consistently across your analyzed repositories.`,
81+
title: "Vibe Coding Identity",
82+
content: `Your aggregated profile identifies you as a ${persona.name}. ${persona.tagline}. This pattern emerges consistently across your analyzed repositories.`,
8383
},
8484
{
85-
title: "Dominant Trait",
86-
content: `Your strongest characteristic is ${dominantAxis[0].replace(/_/g, " ")} with a score of ${dominantAxis[1].score}/100. ${dominantAxis[1].why[0] ?? ""}`,
85+
title: "Strongest Signal",
86+
content: `Your most pronounced trait is ${dominantAxis[0].replace(/_/g, " ")} with a score of ${dominantAxis[1].score}/100. ${dominantAxis[1].why[0] ?? ""}`,
8787
},
8888
{
8989
title: "Repository Breakdown",
9090
content: repoSummary
91-
? `Your style varies across projects: ${repoSummary}${repoBreakdown.length > 3 ? ` and ${repoBreakdown.length - 3} more` : ""}.`
91+
? `Your vibe coding style varies across projects: ${repoSummary}${repoBreakdown.length > 3 ? ` and ${repoBreakdown.length - 3} more` : ""}.`
9292
: "No repository breakdown available.",
9393
},
9494
],
@@ -124,27 +124,29 @@ export async function generateProfileNarrativeWithLLM(params: {
124124
const { provider, apiKey, model, profile } = params;
125125

126126
const systemPrompt = [
127-
"You write a personalized narrative about a developer's SOFTWARE ENGINEERING PATTERNS based on their aggregated profile data.",
128-
"The profile is computed from multiple repository analyses and represents their overall coding identity.",
127+
"You write a personalized narrative about a developer's AI-ASSISTED CODING WORKFLOW based on their aggregated vibe coding profile.",
128+
"The profile measures how developers work with AI coding tools (Claude, Copilot, Cursor, etc.) across multiple repositories.",
129129
"",
130130
"PRIVACY RULES (CRITICAL - VIOLATION MEANS FAILURE):",
131131
"- NEVER mention project names, product names, or repository names",
132132
"- NEVER infer or mention what products, apps, or features the developer builds",
133133
"- NEVER reference business domains, industries, or product categories",
134134
"- Repository identifiers (Repo1, Repo2, etc.) are anonymized - do not try to interpret them",
135-
"- Focus ONLY on: development rhythm, iteration patterns, testing approach, code organization, shipping cadence",
135+
"- Focus ONLY on: AI-assisted workflow patterns, prompt-iterate loops, guardrail habits, session rhythm",
136136
"",
137137
"ALLOWED TOPICS:",
138-
"- How they iterate (small vs large commits, batch vs continuous)",
139-
"- Testing rhythm (when tests appear, test coverage patterns)",
140-
"- Shipping cadence (release frequency, stabilization patterns)",
141-
"- Code organization (refactoring frequency, structural changes)",
142-
"- Collaboration patterns (if visible in data)",
138+
"- How they use AI tools (agentic vs manual, large drops vs incremental edits)",
139+
"- Prompt-fix-run iteration loops and feedback cycles",
140+
"- Guardrail timing (when tests/CI/docs appear relative to AI-generated code)",
141+
"- Session patterns (vibe coding marathons vs steady output)",
142+
"- Planning before prompting (specs-first vs emergent architecture)",
143+
"- Scope of AI-assisted changes (single file vs full-stack slices)",
143144
"",
144145
"CONTENT RULES:",
145146
"- Never infer skill level, code quality, or make judgments",
146-
"- Focus on describing observable engineering patterns",
147+
"- Focus on describing observable AI-assisted coding patterns",
147148
"- Be encouraging but factual. Avoid generic motivational language.",
149+
"- Use vocabulary like: vibe coding, prompt-iterate, agentic workflow, AI-assisted, fix loops, session rhythm",
148150
"",
149151
"Output must be STRICT JSON with this schema:",
150152
'{"summary":"2-3 sentence overview","sections":[{"title":"...","content":"..."}],"highlights":[{"label":"...","value":"...","interpretation":"..."}]}',
@@ -181,9 +183,9 @@ export async function generateProfileNarrativeWithLLM(params: {
181183
"Persona Reasoning:",
182184
profile.persona.why?.join(". ") || "(No reasoning available)",
183185
"",
184-
"Write a personalized narrative about the developer's SOFTWARE ENGINEERING approach and patterns.",
185-
"Focus on: how they iterate, their testing rhythm, shipping cadence, and code organization style.",
186-
"Do NOT interpret repository names or infer what products they build. Focus only on engineering patterns.",
186+
"Write a personalized narrative about the developer's AI-assisted coding workflow and vibe coding patterns.",
187+
"Focus on: how they use AI tools, their prompt-iterate loops, guardrail timing, session rhythm, and scope of changes.",
188+
"Do NOT interpret repository names or infer what products they build. Focus only on AI-assisted workflow patterns.",
187189
].join("\n");
188190

189191
const client = createLLMClient({

apps/web/src/lib/vcp/__tests__/metrics.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,14 @@ describe("computeStrongestAxis", () => {
105105
// =============================================================================
106106

107107
describe("formatStrongestAxis", () => {
108-
it("formats as 'Name Score'", () => {
108+
it("formats as 'HighLabel Name'", () => {
109109
const axes = createMockAxes({
110110
automation_heaviness: { score: 78, level: "high" },
111111
});
112112

113113
const result = formatStrongestAxis(axes);
114114

115-
expect(result).toBe("Automation 78");
115+
expect(result).toBe("AI-Heavy Automation");
116116
});
117117

118118
it("formats different axes correctly", () => {
@@ -122,7 +122,7 @@ describe("formatStrongestAxis", () => {
122122

123123
const result = formatStrongestAxis(axes);
124124

125-
expect(result).toBe("Rhythm 85");
125+
expect(result).toBe("Bursty Rhythm");
126126
});
127127
});
128128

@@ -266,8 +266,8 @@ describe("computePeakLabel", () => {
266266
expect(computePeakLabel("late_nights")).toBe("Late Nights");
267267
});
268268

269-
it("returns 'Varied' for null", () => {
270-
expect(computePeakLabel(null)).toBe("Varied");
269+
it("returns 'All Hours' for null", () => {
270+
expect(computePeakLabel(null)).toBe("All Hours");
271271
});
272272
});
273273

@@ -349,27 +349,27 @@ describe("computeShareCardMetrics", () => {
349349
const result = computeShareCardMetrics(axes, "afternoons");
350350

351351
expect(result).toEqual({
352-
strongest: "Automation 78",
352+
strongest: "AI-Heavy Automation",
353353
style: "Fast Builder",
354354
rhythm: "Mixed",
355355
peak: "Afternoons",
356356
});
357357
});
358358

359-
it("uses 'Varied' for peak when no peakWindow provided", () => {
359+
it("uses 'All Hours' for peak when no peakWindow provided", () => {
360360
const axes = createMockAxes();
361361

362362
const result = computeShareCardMetrics(axes);
363363

364-
expect(result.peak).toBe("Varied");
364+
expect(result.peak).toBe("All Hours");
365365
});
366366

367367
it("handles null peakWindow explicitly", () => {
368368
const axes = createMockAxes();
369369

370370
const result = computeShareCardMetrics(axes, null);
371371

372-
expect(result.peak).toBe("Varied");
372+
expect(result.peak).toBe("All Hours");
373373
});
374374
});
375375

apps/web/src/lib/vcp/metrics.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,12 @@ export function computeStrongestAxis(axes: VibeAxes): StrongestAxis {
4444
}
4545

4646
/**
47-
* Format strongest axis for display (e.g., "Automation 78")
47+
* Format strongest axis for display (e.g., "AI-Heavy Automation")
4848
*/
4949
export function formatStrongestAxis(axes: VibeAxes): string {
50-
const { name, score } = computeStrongestAxis(axes);
51-
return `${name} ${score}`;
50+
const { key } = computeStrongestAxis(axes);
51+
const meta = AXIS_METADATA[key];
52+
return `${meta.highLabel} ${meta.name}`;
5253
}
5354

5455
// =============================================================================
@@ -126,7 +127,7 @@ export function computeRhythmLabel(axes: VibeAxes): RhythmLabel {
126127
// =============================================================================
127128

128129
export type PeakWindow = "mornings" | "afternoons" | "evenings" | "late_nights" | null;
129-
export type PeakLabel = "Mornings" | "Afternoons" | "Evenings" | "Late Nights" | "Varied";
130+
export type PeakLabel = "Mornings" | "Afternoons" | "Evenings" | "Late Nights" | "All Hours";
130131

131132
/**
132133
* Compute a peak time label from timing analysis.
@@ -144,7 +145,7 @@ export function computePeakLabel(peakWindow: PeakWindow): PeakLabel {
144145
case "late_nights":
145146
return "Late Nights";
146147
default:
147-
return "Varied";
148+
return "All Hours";
148149
}
149150
}
150151

@@ -200,7 +201,7 @@ export function analyzePeakWindow(commitTimestamps: string[]): PeakWindow {
200201
// =============================================================================
201202

202203
export interface ShareCardMetrics {
203-
strongest: string; // "Automation 78"
204+
strongest: string; // "AI-Heavy Automation"
204205
style: StyleDescriptor; // "Fast Builder"
205206
rhythm: RhythmLabel; // "Bursty"
206207
peak: PeakLabel; // "Afternoons"

0 commit comments

Comments
 (0)