Skip to main content

Service Architecture

Nectr’s service layer follows a domain-driven design where each service has a single responsibility:

PR Review Service

File: app/services/pr_review_service.py Orchestrates the complete PR review workflow from webhook to GitHub comment.

Class: PRReviewService

Main entry point for PR review processing.
Flow:
  1. Extract PR metadata (number, title, author, files)
  2. Fetch diff + files from GitHub
  3. Parse issue references from PR body (Fixes #123)
  4. Find candidate issues (semantic matching)
  5. Check for open PR conflicts (same files)
  6. Create tool executor for agentic loop
  7. Run AI analysis (standard or parallel mode)
  8. Build review comment with sections:
    • Summary
    • Resolved issues
    • Semantic issue matches
    • Open PR conflicts
    • Similar past work
  9. Post review to GitHub (with inline suggestions)
  10. Index PR in Neo4j
  11. Extract memories to Mem0
  12. Update event status

Class: ReviewToolExecutor

Implements the tool executor protocol for Claude’s agentic loop.

execute()

Routes tool calls to their implementations:
  • read_file → Fetch full source code from GitHub
  • search_project_memory → Query Mem0 for project patterns
  • search_developer_memory → Query Mem0 for developer habits
  • get_file_history → Neo4j file experts + related PRs
  • get_issue_details → Fetch GitHub issue metadata
  • search_open_issues → Keyword search in candidate issues
  • get_linked_issues → MCP client for Linear/GitHub
  • get_related_errors → MCP client for Sentry
Why truncate? Claude has a 200k token context window, but reading 10+ full files can exceed it. Truncation keeps reviews focused.

Helper Functions

Parses Fixes #123, Closes #456, Resolves #789 from PR body + title.
Finds open GitHub issues that might be resolved by this PR (semantic matching).Algorithm:
  1. Fetch up to 50 open issues from GitHub
  2. Build keyword set from PR title + body + file paths
  3. Score each issue by keyword overlap
  4. Return top 8 candidates (overlap ≥ 2 words)
Parses diff patch field to map line content to absolute line numbers.Why? Claude returns line_hint (exact line content) in suggestions. We need to resolve this to a line number for GitHub’s review API.

AI Service

File: app/services/ai_service.py Manages Claude AI interactions with agentic tool execution.

Class: AIServices

analyze_pull_request_agentic()

Agentic review mode (default).Claude receives:
  • PR metadata (title, body, author)
  • Diff (up to 15,000 chars)
  • File list with additions/deletions
  • 8 tools to fetch context on-demand
Agentic loop:
  1. Send initial prompt with diff
  2. Claude analyzes + calls tools
  3. Execute tools → return results
  4. Claude continues analysis
  5. Repeat until stop_reason == "end_turn"
  6. Parse output for verdict + inline suggestions

analyze_pull_request_parallel()

Parallel review mode (opt-in via PARALLEL_REVIEW_AGENTS=true).Runs 3 specialized agents concurrently:
  1. Security agent - Injection, auth flaws, secrets
  2. Performance agent - N+1 queries, memory leaks, O(n²)
  3. Style agent - Missing tests, unclear names, dead code
Then a synthesis agent combines all findings into one review.

Output Parsing

Extracts structured data from Claude’s markdown response:
  1. Verdict - Regex match for **APPROVE**, **REQUEST_CHANGES**, or **NEEDS_DISCUSSION**
  2. Inline suggestions - JSON block in <suggestions>...</suggestions> tags
  3. Semantic issue matches - JSON block in <semantic_issues>...</semantic_issues> tags

Context Service

File: app/services/context_service.py Builds ReviewContext by combining Mem0 semantic memories and Neo4j structural context.

build_review_context()

Parallel queries:
  1. Mem0: Project patterns, decisions, rules
  2. Mem0: Developer-specific patterns, strengths
  3. Neo4j: File experts (developers who touched files most)
  4. Neo4j: Related past PRs (same files)
Returns:

Graph Builder Service

File: app/services/graph_builder.py Builds and queries the Neo4j knowledge graph.

build_repo_graph()

Called when a repo is connected (or on rescan).
  1. Fetch full recursive file tree from GitHub
  2. Create :Repository node
  3. Batch-create :File nodes (chunks of 200)
  4. Create [:CONTAINS] edges
  5. Remove stale files (deleted since last scan)

index_pr()

Called after a PR review is posted.
  1. Create :PullRequest node
  2. Create :Developer node
  3. Create [:AUTHORED_BY] edge
  4. Create [:TOUCHES] edges for changed files
  5. Create [:CLOSES] edges for linked issues

get_file_experts()

Returns developers who most frequently touched the given files.

get_related_prs()

Returns past PRs that touched the same files (structural similarity).

Next Steps

Neo4j Graph

Deep dive into graph schema and queries

Database Schema

PostgreSQL tables and relationships

MCP Client

How Nectr pulls Linear, Sentry, Slack data