---
stepsCompleted: [1, 2, 3, 4, 5, 6, 7, 8]
inputDocuments: [prd.md]
workflowType: 'architecture'
project_name: 'RepoPilot SDK'
user_name: 'Tore'
date: '2026-03-16'
lastStep: 8
status: 'complete'
completedAt: '2026-03-16'
---

# Architecture Decision Document -- RepoPilot SDK

_This document defines the complete architecture for RepoPilot SDK, guiding AI agents through consistent implementation._

## Project Context Analysis

### Requirements Overview

**Functional Requirements:**

The PRD defines 31 functional requirements across 6 capability areas:

| Category | FRs | Architectural Implication |
|----------|-----|--------------------------|
| Code Scanning & Parsing | FR1-FR5 | Java AST parser subsystem; file discovery; multi-byte support |
| Knowledge Graph Construction | FR6-FR11 | Graph data model; relationship extractors; pattern detectors |
| Query & Retrieval | FR12-FR16 | Query engine with ranking; structured output formatter; token budget |
| Index Persistence | FR17-FR20 | Serialization layer; format versioning; staleness detection |
| Plugin & Extensibility | FR21-FR24 | Plugin registry; lifecycle hooks; custom graph node/edge types |
| CLI & Operations | FR25-FR28 | CLI framework; HTTP server; JSON output mode |

Plus 3 FRs (FR29-FR31) for a reference chat interface.

**Non-Functional Requirements:**

| NFR | Target | Architectural Driver |
|-----|--------|---------------------|
| Index build time | <60s for 100K LOC | Parallel file parsing; efficient graph construction |
| Query latency | <500ms | In-memory graph traversal; pre-computed summaries |
| Index load time | <5s | Compact serialization format |
| Memory usage | <2GB for 100K LOC | Memory-efficient graph representation |
| Security | No source code transmitted externally | Fully local scanning pipeline; optional LLM integration |
| Scalability | 500K LOC MVP, 1M+ growth | Tiered storage; streaming parser |
| Concurrency | 10 users MVP, 100+ growth | Async query service; read-only index access |

**Scale & Complexity:**

- Primary domain: Developer Tool (SDK/Library + CLI + HTTP Service)
- Complexity level: Medium -- well-understood technical components (AST parsing, graph construction, query engine) composed in a novel way
- Estimated architectural components: 8 core modules + 2 interface layers (CLI, HTTP)
- Reference codebase: 107 Java files, ~92K LOC, 3 modules with clean dependency graph

### Technical Constraints & Dependencies

- **No JVM dependency at runtime:** The SDK must parse Java source code without requiring a Java runtime -- rules out Eclipse JDT and similar Java-native tools
- **Python-first:** Primary SDK in Python 3.10+; secondary TypeScript SDK is post-MVP
- **Local-only scanning:** Source code never leaves the local environment during scan/index
- **Framework-specific parsing:** Must handle Fujitsu Futurity patterns (CAANSchemaInfo, EJB components, CBS messages) that no existing parser understands
- **Multi-byte support:** Japanese comments and string literals (UTF-8/CJK) throughout the reference codebase
- **Index forward-compatibility:** v1.x indexes loadable by v1.y (y > x)

### Cross-Cutting Concerns Identified

1. **Error handling & graceful degradation** -- Unparseable files fall back to raw-text indexing; never crash the scan pipeline
2. **Source location tracking** -- Every node in the knowledge graph must trace back to file path + line range
3. **Configurable verbosity** -- Token budget for query results; configurable snippet inclusion in indexes
4. **Plugin lifecycle** -- Plugins participate in scan, graph construction, and query phases
5. **Logging & observability** -- Structured logging for scan progress, query performance, plugin execution
6. **UTF-8/CJK correctness** -- End-to-end encoding safety from file read through index serialization to query output

---

## Starter Template & Technology Stack

### Language & Runtime

| Decision | Choice | Rationale |
|----------|--------|-----------|
| Primary language | **Python 3.10+** | PRD requirement; widest AI/ML ecosystem; type hints with modern syntax |
| Type checking | **mypy (strict)** | Enforce correctness in a library; catch integration errors early |
| Package manager | **uv** | Fast dependency resolution; replaces pip+venv; lockfile support |
| Build system | **hatchling** | Modern PEP 517 build backend; simple pyproject.toml config |

### Core Dependencies

| Component | Library | Version | Rationale |
|-----------|---------|---------|-----------|
| Java AST parsing | **tree-sitter + tree-sitter-java** | tree-sitter 0.24+, tree-sitter-java 0.23+ | No JVM required; fast C-based parser; full Java syntax support; Python bindings |
| Graph data model | **networkx** | 3.x | Mature graph library; rich traversal/query algorithms; serializable |
| CLI framework | **click** | 8.x | Composable commands; automatic help generation; widely adopted |
| HTTP server | **FastAPI + uvicorn** | FastAPI 0.115+, uvicorn 0.34+ | Async; auto-OpenAPI 3.0 spec (FR requirement); high performance |
| Serialization | **msgpack** | 1.x | Compact binary format; faster than JSON; schema-compatible evolution |
| Logging | **structlog** | 24.x | Structured JSON logging; context binding; stdlib integration |
| Testing | **pytest + pytest-cov** | pytest 8.x | Standard Python test framework; rich plugin ecosystem |
| Agent layer | **claude-agent-sdk** | 0.1+ | Claude Agent SDK for agentic chat with built-in Read/Glob/Grep + custom MCP tools |
| LLM API | **anthropic** | 0.40+ | Claude API client for direct LLM interactions |

### Why tree-sitter over alternatives

- **javalang** (pure Python): Incomplete Java 17+ support; slow on large files; abandoned maintenance
- **Eclipse JDT**: Requires JVM -- violates NFR constraint
- **ANTLR4 with Java grammar**: Heavier setup; slower than tree-sitter for our read-only parsing use case
- **tree-sitter**: C-native speed; no JVM; incremental parsing; battle-tested across editors (Neovim, Helix, Zed); Python bindings via tree-sitter PyPI package

### Development Tooling

| Tool | Purpose |
|------|---------|
| **ruff** | Linting + formatting (replaces flake8 + black + isort) |
| **mypy** | Static type checking |
| **pytest** | Testing |
| **pre-commit** | Git hooks for lint/type checks |
| **GitHub Actions** | CI/CD pipeline |

---

## Core Architectural Decisions

### Architecture Pattern: Layered Pipeline Architecture

```
                     CLI / HTTP API / Python SDK
                              |
                     +--------+--------+
                     |  Query Engine   |
                     +--------+--------+
                              |
                     +--------+--------+
                     | Knowledge Graph |
                     +--------+--------+
                              |
              +---------------+---------------+
              |               |               |
     +--------+------+ +-----+------+ +------+-------+
     | Java Scanner  | | Relationship | | Plugin      |
     | (tree-sitter) | | Extractors   | | Registry    |
     +---------------+ +--------------+ +-------------+
              |
     +--------+--------+
     | File Discovery   |
     +-----------------+
```

**Data flows top-down during scan, bottom-up during query.**

### Data Architecture

**Knowledge Graph Model (networkx DiGraph):**

Node types:
- `File` -- source file with path, LOC, package
- `Class` -- class/interface/enum with name, modifiers, extends/implements, line range
- `Method` -- method with name, parameters, return type, line range
- `Field` -- field/constant with name, type, value (if static final)
- `CBSSchema` -- CBS message schema with field definitions (CONTENTS array)
- `Package` -- logical grouping

Edge types:
- `CONTAINS` -- File->Class, Class->Method, Class->Field
- `EXTENDS` / `IMPLEMENTS` -- Class->Class
- `CALLS` -- Method->Method
- `REFERENCES` -- Method->Field (constant usage)
- `POPULATES` -- Method->CBSSchema (business logic writes to message fields)
- `IMPORTS` -- File->Class (cross-file dependencies)
- `DEPENDS_ON` -- Package->Package

Each node carries:
- `file_path: str` -- absolute path to source file
- `line_start: int, line_end: int` -- exact source location
- `summary: str` -- auto-generated one-line description
- `raw_snippet: Optional[str]` -- source code snippet (configurable)

**Index Serialization Format:**

```
RepoPilot Index v1 (msgpack)
+-- metadata: {version, build_timestamp, file_count, class_count, ...}
+-- nodes: [{id, type, attributes}]
+-- edges: [{source, target, type, attributes}]
+-- summaries: {node_id: summary_text}
```

Format versioning: major version = breaking change; minor version = additive fields only.

### API Architecture

**Python SDK API (public surface):**

```python
# Core scanning
class RepoScanner:
    def __init__(self, source_path: str | Path, config: ScanConfig | None = None): ...
    def scan(self) -> RepoIndex: ...

# Core querying
class QueryEngine:
    def __init__(self, index: RepoIndex, config: QueryConfig | None = None): ...
    def query(self, question: str, max_tokens: int = 4000) -> StructuredContext: ...

# Index persistence
class RepoIndex:
    def save(self, path: str | Path) -> None: ...
    @classmethod
    def load(cls, path: str | Path) -> RepoIndex: ...
    @property
    def metadata(self) -> IndexMetadata: ...
    def check_staleness(self, source_path: str | Path) -> StalenessReport: ...

# Plugin system
class PatternPlugin(Protocol):
    name: str
    def matches(self, tree: Tree, file_path: str) -> bool: ...
    def extract(self, tree: Tree, file_path: str) -> list[GraphNode | GraphEdge]: ...

# Configuration
@dataclass
class ScanConfig:
    plugins: list[PatternPlugin] = field(default_factory=list)
    include_snippets: bool = True
    max_file_size_kb: int = 5000
    parallel_workers: int = 4

@dataclass
class QueryConfig:
    max_tokens: int = 4000
    include_line_numbers: bool = True
    include_snippets: bool = True
```

**HTTP Query Service API:**

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/query` | POST | Accept natural language question, return StructuredContext |
| `/index/metadata` | GET | Return index statistics |
| `/index/staleness` | POST | Check index freshness against source path |
| `/health` | GET | Service health check |

Authentication: Bearer token via `Authorization` header (configurable, disabled by default for local use).

### Query Engine Strategy

The query engine uses a **hybrid keyword + graph traversal** approach:

1. **Keyword extraction** -- Parse the natural language query into terms; match against node names, summaries, and field names
2. **Graph expansion** -- From matched nodes, traverse relationships (CALLS, POPULATES, REFERENCES) to gather context
3. **Relevance ranking** -- Score nodes by: direct keyword match > 1-hop relationship > 2-hop relationship; weight by node type (Class > Method > Field for overview queries)
4. **Token budgeting** -- Pack results into the configured max_tokens limit, prioritizing highest-ranked nodes
5. **Context assembly** -- Build StructuredContext with: relevant classes (with summaries), method chains, data flows, constant definitions, and source locations

This is MVP query strategy. Post-MVP adds embedding-based semantic search.

### Claude Agent SDK Integration

The agent layer uses Claude Agent SDK with custom MCP tools to provide an intelligent chat interface:

**Architecture:**
```
User Question
       |
Claude Agent SDK (ClaudeSDKClient)
       |
+------+------+
|             |
RepoPilot    Built-in
MCP Tools    Tools (Read, Glob, Grep)
|
+-- query_codebase: Natural language -> StructuredContext
+-- get_class_info: Class name -> detailed class info
+-- get_index_stats: Index metadata
+-- trace_data_flow: Starting point -> relationship chain
```

**How it works:**
1. RepoPilot tools are registered as an in-process MCP server via `create_sdk_mcp_server()`
2. Claude Agent SDK connects to both RepoPilot tools and built-in file tools
3. The agent uses `query_codebase` to search the knowledge graph, then `Read` to verify exact source code
4. Model: `claude-sonnet-4-6` with adaptive thinking for cost-effective reasoning
5. System prompt provides domain context about Fujitsu Futurity, EJB, and CBS patterns

**Custom MCP Tools:**

| Tool | Description |
|------|-------------|
| `query_codebase` | Natural language query -> StructuredContext from knowledge graph |
| `get_class_info` | Get detailed class info (methods, fields, inheritance, relationships) |
| `get_index_stats` | Index metadata (file count, node count, etc.) |
| `trace_data_flow` | BFS traversal from a starting point through CALLS/POPULATES/REFERENCES |

**Usage modes:**
- `repopilot chat --index idx.rpidx --source ./Source` -- Interactive CLI chat
- `repopilot chat --index idx.rpidx --source ./Source -p "question"` -- Single query mode
- Programmatic: `from repopilot.agent.chat import chat; chat(index, source, prompt="...")`

### Authentication & Security

- **Scanning:** Fully local, no network access. File system permissions are the only access control.
- **Index files:** Contain derived metadata by default. Configurable `include_snippets: true` embeds source code -- documentation warns this is for local-only deployments.
- **HTTP service:** Optional bearer token authentication. Default: no auth (localhost only). Production: token required.
- **No telemetry:** Zero data collection. No phone-home. No analytics.

### Error Handling Strategy

```
Level 1 (File): Unparseable Java file -> log warning -> index as raw text (file name, size, package guess from path)
Level 2 (Node): Extraction failure for a specific class/method -> log warning -> skip node -> continue scan
Level 3 (Plugin): Plugin raises exception -> log error -> disable plugin for current file -> continue scan
Level 4 (Index): Corrupted index file -> raise IndexCorruptedError with details -> user must rebuild
Level 5 (Query): No results found -> return empty StructuredContext with suggested_queries hints
```

Never crash the scan pipeline. Always produce the best index possible from available data.

---

## Implementation Patterns & Consistency Rules

### Naming Conventions

| Element | Convention | Example |
|---------|-----------|---------|
| Python modules | snake_case | `knowledge_graph.py`, `java_scanner.py` |
| Classes | PascalCase | `RepoScanner`, `QueryEngine`, `CBSSchemaExtractor` |
| Functions/methods | snake_case | `scan()`, `build_graph()`, `extract_relationships()` |
| Constants | UPPER_SNAKE_CASE | `DEFAULT_MAX_TOKENS`, `INDEX_VERSION` |
| Type aliases | PascalCase | `NodeId`, `GraphEdge`, `StructuredContext` |
| CLI commands | kebab-case | `repopilot scan`, `repopilot query` |
| Test files | `test_<module>.py` | `test_java_scanner.py`, `test_query_engine.py` |
| Test functions | `test_<behavior>` | `test_scan_discovers_all_java_files()` |
| Config files | snake_case | `scan_config.py`, `query_config.py` |

### Code Structure Patterns

**Module structure:**
```python
"""Module docstring -- one line purpose."""

from __future__ import annotations

# stdlib imports
# third-party imports
# local imports

# Constants
# Type definitions
# Main classes/functions
```

**Class pattern:**
```python
class ComponentName:
    """One-line description."""

    def __init__(self, required_arg: Type, config: Config | None = None) -> None:
        self._required = required_arg
        self._config = config or Config()

    def public_method(self) -> ReturnType:
        """One-line description."""
        ...

    def _private_helper(self) -> None:
        ...
```

**Error pattern:**
```python
class RepoPilotError(Exception):
    """Base exception for all RepoPilot errors."""

class ParseError(RepoPilotError):
    """Raised when a Java file cannot be parsed."""
    def __init__(self, file_path: str, reason: str) -> None:
        self.file_path = file_path
        self.reason = reason
        super().__init__(f"Failed to parse {file_path}: {reason}")
```

### Data Flow Patterns

**Scanner pipeline:**
```
discover_files(path) -> list[Path]
    -> parse_file(path) -> Tree (tree-sitter AST)
        -> extract_classes(tree) -> list[ClassNode]
        -> extract_methods(tree) -> list[MethodNode]
        -> extract_fields(tree) -> list[FieldNode]
        -> run_plugins(tree) -> list[GraphNode | GraphEdge]
    -> build_relationships(all_nodes) -> list[GraphEdge]
-> RepoIndex(graph)
```

Each step is a pure function where possible. Side effects (logging, file I/O) are isolated at the boundary.

**Query pipeline:**
```
parse_query(question) -> QueryTerms
    -> match_nodes(terms, graph) -> list[ScoredNode]
    -> expand_graph(scored_nodes, graph) -> list[ContextNode]
    -> rank_results(context_nodes) -> list[RankedNode]
    -> budget_tokens(ranked_nodes, max_tokens) -> list[SelectedNode]
-> StructuredContext
```

### Plugin Pattern

```python
class CBSSchemaPlugin:
    """Extracts CBS message schema patterns from CAANSchemaInfo subclasses."""

    name = "cbs_schema"

    def matches(self, tree: Tree, file_path: str) -> bool:
        """Return True if file contains CAANSchemaInfo subclass."""
        # Check for class_declaration with superclass containing "CAANSchemaInfo"
        ...

    def extract(self, tree: Tree, file_path: str) -> list[GraphNode | GraphEdge]:
        """Extract CBS schema nodes and field definitions."""
        # Parse CONTENTS array -> CBSSchema node with field list
        # Create CONTAINS edges from schema to field nodes
        ...
```

Built-in plugins (shipped with SDK):
1. `CBSSchemaPlugin` -- CAANSchemaInfo/CONTENTS pattern
2. `EJBComponentPlugin` -- ServiceComponentRequestInvoker patterns
3. `ConstantPoolPlugin` -- Static final constant cross-referencing

### Testing Patterns

- Unit tests for each module in isolation (mock tree-sitter trees for parser tests)
- Integration tests using the reference koptBp/koptCommon/koptModel codebase
- Ground truth test suite: 50+ curated Q&A pairs validated against reference codebase
- Test fixtures: small Java files exercising specific patterns (CBS schema, EJB component, constants)
- No mocking of networkx -- test against real graph instances

### Logging Pattern

```python
import structlog
logger = structlog.get_logger()

# In scanner
logger.info("scan.file.parsed", file_path=str(path), classes=len(classes), methods=len(methods))
logger.warning("scan.file.failed", file_path=str(path), error=str(e))

# In query engine
logger.info("query.executed", question=question[:100], results=len(results), latency_ms=elapsed)
```

---

## Project Structure & Boundaries

### Complete Project Directory Structure

```
repopilot/
|-- README.md
|-- LICENSE
|-- pyproject.toml
|-- uv.lock
|-- .python-version
|-- .gitignore
|-- .pre-commit-config.yaml
|-- .github/
|   +-- workflows/
|       |-- ci.yml
|       +-- release.yml
|-- src/
|   +-- repopilot/
|       |-- __init__.py
|       |-- py.typed
|       |-- scanner/
|       |   |-- __init__.py
|       |   |-- discovery.py
|       |   |-- parser.py
|       |   |-- extractor.py
|       |   |-- relationship.py
|       |   +-- scanner.py
|       |-- graph/
|       |   |-- __init__.py
|       |   |-- model.py
|       |   |-- knowledge_graph.py
|       |   +-- index.py
|       |-- query/
|       |   |-- __init__.py
|       |   |-- parser.py
|       |   |-- matcher.py
|       |   |-- expander.py
|       |   |-- ranker.py
|       |   |-- budgeter.py
|       |   |-- context.py
|       |   +-- engine.py
|       |-- plugins/
|       |   |-- __init__.py
|       |   |-- registry.py
|       |   |-- base.py
|       |   |-- cbs_schema.py
|       |   |-- ejb_component.py
|       |   +-- constant_pool.py
|       |-- server/
|       |   |-- __init__.py
|       |   |-- app.py
|       |   |-- routes.py
|       |   +-- auth.py
|       |-- cli/
|       |   |-- __init__.py
|       |   +-- main.py
|       |-- config.py
|       |-- errors.py
|       |-- types.py
|       +-- _version.py
|-- tests/
|   |-- conftest.py
|   |-- fixtures/
|   |   |-- simple_class.java
|   |   |-- cbs_schema.java
|   |   |-- ejb_component.java
|   |   |-- constants.java
|   |   |-- japanese_comments.java
|   |   +-- malformed.java
|   |-- unit/
|   |   |-- test_discovery.py
|   |   |-- test_parser.py
|   |   |-- test_extractor.py
|   |   |-- test_relationship.py
|   |   |-- test_knowledge_graph.py
|   |   |-- test_index.py
|   |   |-- test_query_parser.py
|   |   |-- test_matcher.py
|   |   |-- test_ranker.py
|   |   |-- test_budgeter.py
|   |   |-- test_context.py
|   |   |-- test_plugins.py
|   |   +-- test_config.py
|   |-- integration/
|   |   |-- test_scan_pipeline.py
|   |   |-- test_query_pipeline.py
|   |   |-- test_cli.py
|   |   +-- test_server.py
|   +-- reference/
|       |-- test_reference_codebase.py
|       +-- ground_truth.json
|-- examples/
|   |-- basic_scan.py
|   |-- agent_integration.py
|   |-- custom_plugin.py
|   +-- ci_cd_index.py
+-- docs/
    |-- getting-started.md
    |-- architecture.md
    |-- plugin-guide.md
    +-- api-reference.md
```

### Architectural Boundaries

**API Boundaries:**

- **Public SDK API** (`src/repopilot/__init__.py`): Only `RepoScanner`, `QueryEngine`, `RepoIndex`, `PatternPlugin`, `ScanConfig`, `QueryConfig`, `StructuredContext` are exported. Everything else is internal.
- **HTTP API** (`src/repopilot/server/`): Stateless request-response over the QueryEngine. Index loaded once at startup.
- **CLI** (`src/repopilot/cli/`): Thin wrapper calling SDK API. No business logic in CLI layer.

**Component Boundaries:**

- `scanner/` owns file I/O and AST parsing. Produces `list[GraphNode | GraphEdge]`.
- `graph/` owns the knowledge graph data structure. Consumed by scanner (write) and query (read).
- `query/` owns query parsing, matching, ranking, and context assembly. Read-only access to graph.
- `plugins/` extends scanner behavior. Plugins produce the same `GraphNode | GraphEdge` output.
- `server/` and `cli/` are interface layers. They depend on `scanner/`, `graph/`, and `query/` but never the reverse.

**Data Boundaries:**

- tree-sitter `Tree` objects never escape `scanner/`. The scanner converts them to `GraphNode`/`GraphEdge` at the boundary.
- networkx `DiGraph` is encapsulated inside `KnowledgeGraph`. External code uses typed query methods.
- Serialized index format is owned by `graph/index.py`. Version negotiation happens at load time.

### Requirements to Structure Mapping

| PRD Requirement | Module(s) |
|----------------|-----------|
| FR1-FR5 (Scanning) | `scanner/discovery.py`, `scanner/parser.py`, `scanner/extractor.py` |
| FR6-FR11 (Knowledge Graph) | `scanner/relationship.py`, `graph/`, `plugins/cbs_schema.py`, `plugins/ejb_component.py`, `plugins/constant_pool.py` |
| FR12-FR16 (Query) | `query/` (all modules) |
| FR17-FR20 (Index) | `graph/index.py` |
| FR21-FR24 (Plugins) | `plugins/registry.py`, `plugins/base.py` |
| FR25-FR28 (CLI) | `cli/main.py` |
| FR29-FR31 (Chat) | `examples/agent_integration.py` (reference implementation, not core SDK) |

### Integration Points

**Internal Communication:**
- Scanner -> Graph: Scanner calls `KnowledgeGraph.add_node()` / `add_edge()` to populate the graph
- Query -> Graph: QueryEngine calls `KnowledgeGraph.find_nodes()` / `traverse()` for read-only access
- Plugins -> Scanner: Scanner calls `plugin.matches()` then `plugin.extract()` during file processing
- CLI/Server -> SDK: Import `RepoScanner`, `QueryEngine`, `RepoIndex` from public API

**External Integrations:**
- **tree-sitter**: Called inside `scanner/parser.py` only. Initialized once per scan.
- **networkx**: Used inside `graph/knowledge_graph.py` only. Never exposed in public API.
- **FastAPI**: Used inside `server/` only. Optional dependency (not required for SDK-only usage).
- **LLM providers**: Not integrated in core SDK. The `examples/agent_integration.py` shows how consumers feed `StructuredContext` to an LLM.

**Data Flow:**

```
Java Source Files
       | (file I/O)
scanner/discovery.py -> list[Path]
       |
scanner/parser.py -> tree-sitter Tree
       |
scanner/extractor.py + plugins/ -> list[GraphNode | GraphEdge]
       |
scanner/relationship.py -> list[GraphEdge] (cross-file)
       |
graph/knowledge_graph.py -> KnowledgeGraph (networkx DiGraph)
       |
graph/index.py -> RepoIndex (graph + metadata)
       | (save/load via msgpack)
index.rpidx file
       |
query/engine.py -> StructuredContext (JSON-serializable dict)
       |
CLI output / HTTP response / Python API return
```

### Development Workflow Integration

**Development Server:**
```bash
uv run repopilot serve --index ./index.rpidx --port 8080 --reload
```

**Build Process:**
```bash
uv build                    # Build wheel + sdist
uv run pytest               # Run all tests
uv run mypy src/            # Type checking
uv run ruff check src/      # Linting
```

**Deployment:**
- PyPI: `uv publish` on git tag via GitHub Actions
- CLI binary: Future (post-MVP) -- standalone via PyInstaller or similar

---

## Architecture Validation Results

### Coherence Validation

**Decision Compatibility:**
All technology choices work together without conflicts:
- Python 3.10+ supports all chosen libraries (tree-sitter, networkx, FastAPI, click, msgpack, structlog)
- tree-sitter Python bindings are mature and actively maintained
- networkx serialization aligns with msgpack choice (nodes/edges as dicts)
- FastAPI + uvicorn is the standard async Python web stack
- ruff + mypy + pytest is the modern Python quality toolchain

**Pattern Consistency:**
- All modules follow the same naming conventions (snake_case modules, PascalCase classes)
- Pipeline pattern (discover -> parse -> extract -> build -> query) is consistent throughout
- Error handling follows the same graceful degradation strategy at every level
- Plugin pattern produces the same GraphNode/GraphEdge types as built-in extractors

**Structure Alignment:**
- `src/` layout with `src/repopilot/` follows modern Python packaging best practices
- Test structure mirrors source structure (unit/integration/reference)
- Each architectural component has a clear home directory
- No circular dependencies between modules

### Requirements Coverage Validation

**Functional Requirements Coverage:**
- FR1-FR5 (Scanning): Covered by `scanner/` module with tree-sitter parser
- FR6-FR11 (Knowledge Graph): Covered by `graph/` + `plugins/` with 3 built-in pattern plugins
- FR12-FR16 (Query): Covered by `query/` module with hybrid keyword+graph approach
- FR17-FR20 (Index): Covered by `graph/index.py` with msgpack serialization and staleness detection
- FR21-FR24 (Plugins): Covered by `plugins/` with Protocol-based plugin API
- FR25-FR28 (CLI): Covered by `cli/main.py` with click commands
- FR29-FR31 (Chat): Covered by `examples/agent_integration.py` as reference implementation

**Non-Functional Requirements Coverage:**
- Performance: Parallel file parsing (ScanConfig.parallel_workers); in-memory graph; token budgeting
- Security: Local-only scanning; no telemetry; optional auth on HTTP service
- Scalability: Graph can handle 500K LOC in memory (<2GB); tiered storage planned for growth
- Integration: PEP 561 type stubs; OpenAPI 3.0 spec via FastAPI; JSON CLI output

### Implementation Readiness Validation

**Decision Completeness:**
- All critical technology choices documented with versions
- Implementation patterns comprehensive with code examples
- Naming conventions cover all code elements
- Error handling strategy defined for all failure modes

**Structure Completeness:**
- Every file and directory defined in project tree
- All FRs mapped to specific modules
- Integration points clearly specified
- Test organization matches source organization

**Pattern Completeness:**
- Scanner pipeline pattern fully specified
- Query pipeline pattern fully specified
- Plugin pattern with Protocol definition
- Logging pattern with structlog
- Error hierarchy pattern

### Gap Analysis Results

**No critical gaps identified.**

**Important notes for implementation:**
- The reference chat interface (FR29-FR31) is intentionally placed in `examples/` rather than core SDK -- this is a demonstration, not a maintained component
- TypeScript SDK (secondary language from PRD) is explicitly post-MVP and not included in this architecture
- Embedding-based semantic search is post-MVP; the MVP query engine uses keyword + graph traversal only

### Architecture Completeness Checklist

**Requirements Analysis**
- [x] Project context thoroughly analyzed
- [x] Scale and complexity assessed
- [x] Technical constraints identified
- [x] Cross-cutting concerns mapped

**Architectural Decisions**
- [x] Critical decisions documented with versions
- [x] Technology stack fully specified
- [x] Integration patterns defined
- [x] Performance considerations addressed

**Implementation Patterns**
- [x] Naming conventions established
- [x] Structure patterns defined
- [x] Communication patterns specified
- [x] Process patterns documented

**Project Structure**
- [x] Complete directory structure defined
- [x] Component boundaries established
- [x] Integration points mapped
- [x] Requirements to structure mapping complete

### Architecture Readiness Assessment

**Overall Status:** READY FOR IMPLEMENTATION

**Confidence Level:** High -- all requirements covered, no blocking gaps, technology choices well-understood and proven

**Key Strengths:**
- Clean layered architecture with clear boundaries
- Plugin system enables extensibility without core changes
- Technology choices are all mature, well-maintained Python libraries
- Project structure maps directly to PRD requirements
- Graceful degradation at every level prevents pipeline failures

**Areas for Future Enhancement:**
- Embedding-based semantic search (post-MVP)
- TypeScript SDK (post-MVP)
- Incremental indexing on git diff (post-MVP)
- Tiered storage for 1M+ LOC codebases (growth phase)

### Implementation Handoff

**AI Agent Guidelines:**
- Follow all architectural decisions exactly as documented
- Use implementation patterns consistently across all components
- Respect project structure and boundaries
- Refer to this document for all architectural questions
- Start with the scanner pipeline (discovery -> parser -> extractor), then graph, then query engine, then CLI/server

**First Implementation Priority:**
1. Set up project skeleton with pyproject.toml and uv
2. Implement `scanner/discovery.py` and `scanner/parser.py` (tree-sitter integration)
3. Implement `graph/model.py` and `graph/knowledge_graph.py`
4. Implement `scanner/extractor.py` to connect parsing to graph
5. Implement `plugins/cbs_schema.py` against reference codebase fixtures
6. Implement `query/engine.py` with basic keyword matching
7. Implement `graph/index.py` for save/load
8. Implement `cli/main.py` for scan and query commands
9. Build integration tests against reference codebase
10. Implement `server/app.py` for HTTP query service
