> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Nectr-AI/nectr-ai-pr-review-agent/llms.txt
> Use this file to discover all available pages before exploring further.

# Contributor Analytics

> Get detailed per-developer insights from AI memory

## Overview

Retrieve comprehensive contributor profiles built from Mem0 AI memory, including developer patterns, strengths, and historical activity. This endpoint is designed for team leaders to understand their team's expertise and contribution patterns.

## Authentication

Requires a valid JWT token in the `Authorization` header:

```
Authorization: Bearer YOUR_JWT_TOKEN
```

## Query Parameters

<ParamField query="repo" type="string" required>
  Repository to query in `owner/repo` format (e.g., "acme/api-server")
</ParamField>

<ParamField query="page" type="integer" default="1">
  Page number for pagination (1-indexed)
</ParamField>

<ParamField query="per_page" type="integer" default="20">
  Number of contributors per page (1-100)
</ParamField>

## Response

<ResponseField name="repo" type="string">
  Repository full name (owner/repo)
</ResponseField>

<ResponseField name="contributor_count" type="integer">
  Total number of contributors with AI memory
</ResponseField>

<ResponseField name="page" type="integer">
  Current page number
</ResponseField>

<ResponseField name="per_page" type="integer">
  Items per page
</ResponseField>

<ResponseField name="total_pages" type="integer">
  Total number of pages
</ResponseField>

<ResponseField name="contributors" type="array">
  Array of contributor profiles
</ResponseField>

<ResponseField name="contributors[].username" type="string">
  GitHub username
</ResponseField>

<ResponseField name="contributors[].profile_summary" type="string">
  AI-generated profile summary of the developer's contribution style
</ResponseField>

<ResponseField name="contributors[].patterns" type="array">
  Array of identified developer patterns (coding habits, preferences, common approaches)
</ResponseField>

<ResponseField name="contributors[].strengths" type="array">
  Array of developer strengths (areas of expertise, technical skills)
</ResponseField>

<ResponseField name="contributors[].pr_count" type="integer">
  Total number of PRs submitted by this contributor
</ResponseField>

<ResponseField name="contributors[].commit_count" type="integer">
  Total number of commits by this contributor
</ResponseField>

<ResponseField name="contributors[].last_seen_pr" type="integer">
  Most recent PR number from this contributor
</ResponseField>

## Example Request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.nectr.ai/api/v1/analytics/contributors?repo=acme/api-server&page=1&per_page=10" \
    -H "Authorization: Bearer YOUR_JWT_TOKEN"
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://api.nectr.ai/api/v1/analytics/contributors",
      headers={"Authorization": f"Bearer {token}"},
      params={
          "repo": "acme/api-server",
          "page": 1,
          "per_page": 10
      }
  )

  data = response.json()
  for contributor in data['contributors']:
      print(f"{contributor['username']}: {contributor['pr_count']} PRs")
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.nectr.ai/api/v1/analytics/contributors?repo=acme/api-server&page=1&per_page=10',
    {
      headers: {
        'Authorization': `Bearer ${token}`
      }
    }
  );

  const data = await response.json();
  data.contributors.forEach(contributor => {
    console.log(`${contributor.username}: ${contributor.pr_count} PRs`);
  });
  ```
</CodeGroup>

## Example Response

```json theme={null}
{
  "repo": "acme/api-server",
  "contributor_count": 12,
  "page": 1,
  "per_page": 10,
  "total_pages": 2,
  "contributors": [
    {
      "username": "johndoe",
      "profile_summary": "Experienced backend engineer focused on API design and database optimization. Consistently delivers well-tested, production-ready code with comprehensive documentation.",
      "patterns": [
        "Prefers comprehensive error handling with custom exception classes",
        "Always includes unit tests and integration tests for new features",
        "Favors async/await patterns for database operations"
      ],
      "strengths": [
        "Database schema design and optimization",
        "RESTful API architecture",
        "Performance profiling and optimization"
      ],
      "pr_count": 47,
      "commit_count": 312,
      "last_seen_pr": 42
    },
    {
      "username": "janedoe",
      "profile_summary": "Frontend specialist with strong TypeScript skills. Known for creating polished, accessible user interfaces with excellent attention to detail.",
      "patterns": [
        "Uses functional React components with hooks",
        "Implements comprehensive accessibility features (ARIA labels, keyboard navigation)",
        "Prefers composition over inheritance for component architecture"
      ],
      "strengths": [
        "TypeScript type safety and advanced patterns",
        "CSS-in-JS and responsive design",
        "State management with Redux and Context API"
      ],
      "pr_count": 38,
      "commit_count": 241,
      "last_seen_pr": 39
    }
  ]
}
```

## Memory Types

The contributor data is built from three types of AI memories:

### contributor\_profile

High-level summary of the developer's contribution style, generated from analyzing their PR history.

### developer\_pattern

Specific coding patterns and habits identified across multiple PRs:

* Architectural preferences
* Code organization style
* Testing approaches
* Common techniques

### developer\_strength

Technical areas where the developer excels:

* Technology expertise
* Problem-solving domains
* Architectural skills

## Error Responses

### Repository Not Connected

```json theme={null}
{
  "detail": "Repo not connected or access denied"
}
```

HTTP Status: `403 Forbidden`

### Memory Layer Unavailable

```json theme={null}
{
  "repo": "acme/api-server",
  "contributor_count": 0,
  "contributors": [],
  "note": "Memory layer not configured"
}
```

HTTP Status: `200 OK` (graceful degradation)

## Use Cases

### Team Overview Dashboard

```python theme={null}
data = get_contributors(repo="acme/api-server")

print(f"Team Overview - {data['repo']}")
print(f"Total Contributors: {data['contributor_count']}")
print()

for contributor in data['contributors'][:5]:
    print(f"👤 {contributor['username']}")
    print(f"   PRs: {contributor['pr_count']} | Commits: {contributor['commit_count']}")
    print(f"   Profile: {contributor['profile_summary']}")
    if contributor['strengths']:
        print(f"   Strengths: {', '.join(contributor['strengths'][:3])}")
    print()
```

### Code Review Assignment

```python theme={null}
def suggest_reviewer(pr_files, contributors):
    """Suggest the best reviewer based on file expertise."""
    for contributor in contributors:
        for strength in contributor['strengths']:
            if any(tech in strength.lower() for tech in ['database', 'sql']):
                if any('db' in f or 'models' in f for f in pr_files):
                    return contributor['username']
    return contributors[0]['username']  # fallback to most active

data = get_contributors(repo="acme/api-server")
pr_files = ['app/models/user.py', 'app/db/migrations/001.sql']

reviewer = suggest_reviewer(pr_files, data['contributors'])
print(f"Suggested reviewer: {reviewer}")
```

### Skill Gap Analysis

```python theme={null}
data = get_contributors(repo="acme/api-server")

all_strengths = {}
for contributor in data['contributors']:
    for strength in contributor['strengths']:
        all_strengths[strength] = all_strengths.get(strength, 0) + 1

print("Team Skills Coverage:")
for skill, count in sorted(all_strengths.items(), key=lambda x: x[1], reverse=True):
    coverage = (count / data['contributor_count']) * 100
    print(f"{skill}: {count} devs ({coverage:.0f}% coverage)")
```

## Pagination Example

```python theme={null}
def get_all_contributors(repo):
    """Fetch all contributors across all pages."""
    all_contributors = []
    page = 1
    
    while True:
        data = get_contributors(repo=repo, page=page, per_page=20)
        all_contributors.extend(data['contributors'])
        
        if page >= data['total_pages']:
            break
        page += 1
    
    return all_contributors
```
