Skip to main content

Overview

The Intel page provides AI-driven analysis of your job search activity, market trends, and actionable recommendations to improve your success rate.
Intel data is generated by analyzing your application history, success patterns, and comparing them to market benchmarks.

Tabs

The Intel page is organized into four tabs:
High-level insights, patterns, benchmarks, and profile gaps.
// Tab navigation (src/views/app/intel.tsx:18-68)
const TABS: { id: IntelTab; label: string }[] = [
  { id: 'overview',        label: 'Overview' },
  { id: 'market',          label: 'Market' },
  { id: 'companies',       label: 'Companies' },
  { id: 'recommendations', label: 'Recommendations' },
]

const [activeTab, setActiveTab] = useState<IntelTab>('overview')

Overview Tab

Key Insights Banner

The top banner displays one rotating insight at a time:
// Insight types (src/lib/types/intel.ts:10-18)
export interface KeyInsight {
  id: string
  type: 'opportunity' | 'warning' | 'achievement' | 'suggestion'
  title: string
  description: string
  impact: 'high' | 'medium' | 'low'
  actionLabel?: string
  actionHref?: string
}
Example Insights:
  • Opportunity: “Companies are hiring 34% more engineers this month — increase your application rate.”
  • Warning: “Your interview rate dropped to 12% this week. Review your application targeting.”
  • Achievement: “You’ve reached 50 applications! You’re in the top 10% of active users.”
  • Suggestion: “Try applying on Tuesdays — your response rate is 47% higher.”

Pattern Cards

Three cards display behavioral patterns extracted from your data:

Best Time to Apply

Primary Value: "Tuesday" Secondary Value: "47%" response rate Benchmark: "vs 31% market avg"

Top-Performing Source

Primary Value: "LinkedIn" Secondary Value: "68%" interview rate Benchmark: "vs 41% avg"

Role Fit Pattern

Primary Value: "Senior" Secondary Value: "83%" avg match score Benchmark: "Best fit level"
// Pattern card data structure (src/lib/types/intel.ts:20-30)
export interface PatternCard {
  id: string
  title: string           // "Best Time to Apply"
  subtitle: string        // "Your optimal window"
  primaryValue: string    // "Tuesday"
  primaryLabel: string    // "Best day"
  secondaryValue: string  // "47%"
  secondaryLabel: string  // "Response rate"
  benchmark?: string      // "vs 31% market avg"
  trend: 'up' | 'down' | 'neutral'
}

Benchmark Grid

Compares your performance against market averages:
1

Response Rate

Your Value: 68% Market Value: 41% Status: Above average ✓
2

Time to Interview

Your Value: 8.2 days Market Value: 12.5 days Status: Faster than market ✓
3

Application Volume

Your Value: 42 per month Market Value: 35 per month Status: Above average ✓
// Benchmark data structure (src/lib/types/intel.ts:32-42)
export interface PerformanceBenchmark {
  metric: string          // "Response Rate"
  yourValue: string       // "68%"
  yourRaw: number         // 68
  marketValue: string     // "41%"
  marketRaw: number       // 41
  unit: string            // "%" or "days"
  trend: TrendDirection
  better: boolean         // true if higher is better
}

Profile Gaps

Identifies skills and requirements you’re missing based on jobs you’ve saved/applied to:
// Profile gap structure (src/lib/types/intel.ts:44-50)
export interface ProfileGap {
  requirement: string     // "Project Management"
  demandCount: number     // 12 (jobs that mention it)
  yourLevel: 'strong' | 'present' | 'weak' | 'missing'
  jobsAffected: number    // 18 (jobs where this gap matters)
  priority: 'high' | 'medium' | 'low'
}
Example Gaps:
  • High Priority: “Kubernetes” — missing, affects 18/42 jobs
  • Medium Priority: “GraphQL” — weak, affects 9/42 jobs
  • Low Priority: “Vue.js” — present, affects 3/42 jobs

Market Tab

Analyzes broader job market trends:

Market Stats

Four key market indicators:
// Market stat structure (src/lib/types/intel.ts:52-59)
export interface MarketStat {
  label: string           // "Market Heat"
  value: string           // "78%"
  change: number          // 12
  changeLabel: string     // "vs last month"
  direction: 'up' | 'down' | 'neutral'
}

Market Heat

78% — 12% increase vs last month

Avg Time to Hire

14.2 days — 3 days faster

Competition Index

3.2 applicants/role — 8% decrease

Salary Trend

+7.5% year-over-year
Time-series chart showing status distribution over time:
// Hiring trend data (src/lib/types/intel.ts:61-66)
export interface HiringTrendPoint {
  date: string
  applied: number
  interview: number
  offer: number
  rejected: number
}

Top Companies

Ranked list of companies with highest hiring activity:
// Top company structure (src/lib/types/intel.ts:68-74)
export interface TopCompany {
  rank: number            // 1
  name: string            // "Stripe"
  openRoles: number       // 47
  change: number          // 23 (% change in open roles)
  direction: 'up' | 'down' | 'neutral'
}
1

#1 Stripe

47 open roles (+23%)
2

#2 Shopify

38 open roles (+15%)
3

#3 Notion

29 open roles (+8%)

Skill Demand

Most in-demand skills in your target market:
// Skill demand structure (src/lib/types/intel.ts:76-80)
export interface SkillDemand {
  skill: string
  count: number           // Number of jobs mentioning this skill
  relevantToYou: boolean  // true if appears in your saved jobs
}
Skills marked as relevant to you are highlighted — these align with your interests.

Companies Tab

Tracks your interaction history with each company:
// Company history structure (src/lib/types/intel.ts:82-95)
export interface CompanyHistory {
  companyId: string
  name: string
  initials: string        // "ST" for Stripe
  applications: number    // Total applications
  interviews: number      // Reached interview stage
  responseRate: number    // 0-100
  avgResponseDays: number // Days between apply and response
  lastActivity: string    // "3d ago"
  status: 'active' | 'cold' | 'rejected' | 'offer'
  recommendation?: string // "Strong match — keep applying"
}

Company Status Indicators

Active

Recent applications with ongoing conversations

Cold

No response in 30+ days

Rejected

Received rejection from this company

Offer

Offer received from this company

Recommendations Tab

Prioritized list of actionable recommendations:

Recommendation Structure

// Recommendation structure (src/lib/types/intel.ts:97-107)
export interface Recommendation {
  id: string
  category: 'timing' | 'source' | 'profile' | 'approach' | 'network'
  title: string
  description: string
  effort: 'low' | 'medium' | 'high'
  impact: 'high' | 'medium' | 'low'
  actionLabel?: string
  dismissed?: boolean
}

Recommendation Categories

Optimize when you apply:
  • “Apply between 9-11am for 34% higher response rates”
  • “Avoid Fridays — your success rate is 23% lower”

Impact & Effort Labels

const IMPACT_CONFIG = {
  high:   { label: 'High Impact',   className: 'bg-terminal-500/10 text-terminal-500' },
  medium: { label: 'Med Impact',    className: 'bg-blue-500/10 text-blue-400'         },
  low:    { label: 'Low Impact',    className: 'bg-muted/40 text-muted-foreground'    },
}
const EFFORT_CONFIG = {
  low:    { label: 'Easy win',    dot: 'bg-terminal-500' },
  medium: { label: 'Some effort', dot: 'bg-yellow-400'   },
  high:   { label: 'High effort', dot: 'bg-red-400'      },
}

Sorting

Recommendations are sorted by:
  1. Impact (high → medium → low)
  2. Effort (low → medium → high)
// Sorting logic (src/components/intel/tabs/recommendations-tab.tsx:37-45)
const active = data.recommendations
  .filter(r => !dismissed.includes(r.id))
  .sort((a, b) => {
    const impactOrder = { high: 0, medium: 1, low: 2 }
    const effortOrder = { low: 0, medium: 1, high: 2 }
    if (impactOrder[a.impact] !== impactOrder[b.impact]) {
      return impactOrder[a.impact] - impactOrder[b.impact]
    }
    return effortOrder[a.effort] - effortOrder[b.effort]
  })
Focus on high impact + low effort recommendations first for quick wins.

Dismissing Recommendations

Click the X button to dismiss a recommendation:
// Dismiss handler (src/components/intel/tabs/recommendations-tab.tsx:33-34)
const [dismissed, setDismissed] = useState<string[]>([])

<button onClick={() => setDismissed(d => [...d, rec.id])}>
  <X className="w-3 h-3" />
</button>

Data Refresh

Click the Refresh button in the page header to re-fetch Intel data:
// Refresh action (src/views/app/intel.tsx:27-38)
const { data, isLoading, refresh } = useIntel()

<Button variant="outline" size="icon" onClick={() => refresh()}>
  <RefreshCw className={cn("h-4 w-4", isLoading && "animate-spin")} />
</Button>
Intel data is cached for 15 minutes by default to avoid excessive AI computation.

API Endpoint

GET /api/ai/insights

Fetches all Intel data for the authenticated user. Response:
{
  "keyInsights": [
    {
      "id": "ins_1",
      "type": "opportunity",
      "title": "Market Heating Up",
      "description": "Companies are hiring 34% more engineers this month.",
      "impact": "high"
    }
  ],
  "patterns": [
    {
      "id": "pat_1",
      "title": "Best Time to Apply",
      "primaryValue": "Tuesday",
      "secondaryValue": "47%",
      "benchmark": "vs 31% avg",
      "trend": "up"
    }
  ],
  "benchmarks": [],
  "profileGaps": [],
  "marketStats": [],
  "hiringTrends": [],
  "topCompanies": [],
  "skillDemand": [],
  "companyHistory": [],
  "recommendations": []
}
// React Query hook (src/hooks/use-intel.ts)
import { useQuery } from '@tanstack/react-query'
import type { IntelData } from '@/src/lib/types/intel'

export function useIntel() {
  const query = useQuery({
    queryKey: ['intel'],
    queryFn: async () => {
      const res = await fetch('/api/ai/insights')
      if (!res.ok) throw new Error('Failed to fetch intel')
      return res.json() as Promise<IntelData>
    },
    staleTime: 15 * 60 * 1000, // 15 minutes
  })

  return {
    ...query,
    refresh: () => query.refetch(),
  }
}

Next Steps

AI Scoring

Learn how match scores are calculated

Dashboard

Track your job search metrics

Tracker

Manage your applications

Insights API

API reference for Intel data

Build docs developers (and LLMs) love