<!-- STATUS: COMPLETE -->

# Unfamiliar v0.1.0 — Review Guide

> **Time to complete:** ~2 hours across multiple sessions
> **Last updated:** 2026-03-21
> **Build:** 20 phases, 1059 tests, MVP complete

---

## Table of Contents

1. [Quick Start](#1-quick-start) (~5 min)
2. [Feature Testing](#2-feature-testing) (~20 min)
3. [Code Understanding](#3-code-understanding) (~45 min)
4. [Testing Guide](#4-testing-guide) (~10 min)
5. [Known Issues](#5-known-issues) (~5 min)
6. [Next Steps](#6-next-steps) (~5 min)

---

## 1. Quick Start

⏱️ ~5 minutes

### Prerequisites

- [x] Python 3.11+ installed
- [x] Git installed
- [x] An LLM API key (Anthropic recommended, GLM/Zhipu also supported)
- [x] A git repository to investigate (any codebase — your own or open source)

### Setup Steps

1. **Install the package:**
   ```bash
   pip install -e .
   ```
   - [x] Verify: `unfamiliar --version` → `unfamiliar 0.1.0`

2. **Set your API key:**
   ```bash
   export ANTHROPIC_API_KEY="sk-ant-..."
   # Or for GLM: export GLM_API_KEY="your-key"
   ```
   - [x] Verify: `echo $ANTHROPIC_API_KEY` shows your key

3. **Configure the provider** (optional — defaults to Anthropic):
   ```bash
   # Config is auto-created at ~/.unfamiliar/config.toml
   # Edit to change provider, token budget, or model
   cat ~/.unfamiliar/config.toml
   ```

4. **Run your first investigation:**
   ```bash
   unfamiliar investigate /path/to/any/git/repo
   ```
   - [x] Expected output:
     - "Starting investigation for: /path/to/repo"
     - Progress messages: analyzing → briefing → missions
     - "Investigation ready: N available to start"
     - TUI launches with Film Noir themed interface

5. **Inside the TUI**, type `investigate` (or `next`) to see available missions.
   - [x] You see a numbered list of investigation missions
   - [x] Type a number to start a mission
   - [x] Type `file report` (or `complete`) to mark it done
   - [x] Type `dossier` (or `status`) to see progress
   - [x] Type `quit` to exit

### Troubleshooting

- **"No API key found"** → Set the correct env var for your provider
- **Rate limit errors (429)** → Wait and retry, or switch to a paid tier
- **"Not a git repository"** → Target must contain a `.git/` directory
- **Config issues** → Delete `~/.unfamiliar/config.toml` and re-run (it auto-regenerates)

---

## 2. Feature Testing

⏱️ ~20 minutes total

### 2.1 Campaign Creation (5 min)

**What it does:** Analyzes a git repo, generates an LLM briefing, creates missions across 7 investigation categories, and persists everything to SQLite.

**Test steps:**
- [x] Run `unfamiliar investigate /path/to/repo` on a medium-sized repo (50-200 files)
- [x] Observe progress messages flowing in order: analyzing → briefing → missions → saving
- [x] Verify "Investigation ready" shows missions available
- [x] Run `unfamiliar campaigns` — your campaign appears as ACTIVE
- [x] Run `unfamiliar investigate /path/to/same/repo` again — should prompt "Overwrite and start fresh?"
- [x] Choose "No" — campaign is preserved
- [x] Verify: campaign data at `~/.unfamiliar/campaigns/<repo-name>-<hash>/`

**Expected results:**
- 30-60 missions generated across 7 categories (Architecture, Domain, Data Flow, Dependencies, Conventions, Testing, Technical Debt)
- 3-10 mission chains (ordered learning paths)
- Root missions (no prerequisites) start as AVAILABLE
- Non-root missions start as LOCKED

**Common issues:**
- Large repos (500+ files) may exceed token budget → missions still generated, context truncated
- GLM provider may need lower token budget or paid tier for large repos
- "0 available" → likely a chain-linking issue (see Known Issues)

### 2.2 TUI Investigation Session (5 min)

**What it does:** Interactive Film Noir themed terminal for working through missions.

**Test steps:**
- [x] Launch via `unfamiliar investigate <repo>` or `unfamiliar resume`
- [x] Verify layout: header (top), content (left), command reference (right), input (bottom)
- [x] Type `investigate` → see available missions listed with numbers
- [x] Type a number (e.g., `1`) → mission details shown (title, category, difficulty, instructions, file references)
- [x] Type `file report` → mission marked complete, unlocked missions announced
- [x] Type `dossier` → campaign progress shown per category
- [x] Type `the brief` → codebase briefing displayed
- [x] Type `help` → man-page style command reference shown
- [x] Type `?` key → same as help
- [x] Type `quit` or press `q` → quit confirmation modal appears

**Expected results:**
- All commands resolve themed aliases (Film Noir vocabulary)
- Progress persists — exit and `unfamiliar resume` picks up where you left off
- Missions unlock progressively as prerequisites are completed
- Toast notifications appear when missions are unlocked

**Common issues:**
- Arrow keys don't navigate modal buttons (Tab works) — known limitation
- No keyboard shortcut to refocus command input after Escape — use mouse click

### 2.3 Mission Lifecycle (5 min)

**What it does:** Manages mission status transitions: LOCKED → AVAILABLE → IN_PROGRESS → COMPLETED.

**Test steps:**
- [x] Start a mission by number → status changes to IN_PROGRESS
- [x] Exit and resume → in-progress mission detected, welcome message reflects it
- [x] Complete the mission with `file report` → status changes to COMPLETED
- [x] Check if dependent missions unlocked → new missions appear in `investigate` list
- [x] Try `break in <id>` on a locked mission → force-unlocked to AVAILABLE
- [x] Try completing a locked mission → error message shown

**Expected results:**
- AVAILABLE → IN_PROGRESS on selection
- IN_PROGRESS → COMPLETED on `file report`
- LOCKED dependents → AVAILABLE when all prerequisites COMPLETED
- Force unlock bypasses prerequisites

### 2.4 Campaign End and Reopen (3 min)

**What it does:** Close a campaign ("case closed") and reopen it later.

**Test steps:**
- [x] Type `end campaign` (or `close the case`) in TUI → confirmation modal
- [x] Confirm → campaign status changes to CLOSED
- [x] Run `unfamiliar campaigns` → campaign shows as CLOSED
- [x] Run `unfamiliar reopen /path/to/repo` → campaign reopened to ACTIVE
- [x] Run `unfamiliar resume` → can continue investigation

**Expected results:**
- Campaign transitions: ACTIVE → CLOSED → ACTIVE
- All mission progress preserved across close/reopen

### 2.5 CLI Commands (2 min)

**What it does:** Non-TUI command-line operations.

**Test steps:**
- [x] `unfamiliar --version` → `unfamiliar 0.1.0`
- [x] `unfamiliar campaigns` → lists all campaigns with status, progress, date
- [x] `unfamiliar resume` → resumes most recent ACTIVE campaign
- [x] `unfamiliar reopen <repo>` → reopens a closed campaign
- [x] `unfamiliar investigate <non-git-dir>` → error "not a git repository"

**Expected results:**
- Each command validates config before proceeding
- Orphaned campaigns (deleted repos) shown with warning
- Clear error messages for all failure modes

---

## 3. Code Understanding

⏱️ ~45 minutes total. Read in order — each level builds on the previous.

### Level 1: Data Structures (~8 min)

**Start here.** Understand what data Unfamiliar works with before reading how it flows.

#### `src/unfamiliar/constants.py` — Domain enums
⏱️ 2 min | 122 lines

- **Purpose:** All domain enums and scoring constants. The source of truth for what values exist.
- **Key concepts:**
  - `InvestigationCategory` — the 7 investigation types (architecture through technical_debt)
  - `MissionStatus` — LOCKED → AVAILABLE → IN_PROGRESS → COMPLETED
  - `CampaignStatus` — INITIALIZING → ACTIVE → CLOSED
  - `MissionDifficulty` — QUICK (15 min), MEDIUM (30 min), DEEP_DIVE (45 min)
- **What to notice:** `StrEnum` means enum values are strings, directly stored in SQLite. v1.1 enums (`CompletionMethod.ANNOTATION`, `CharacterArchetype`) are defined but unused.
- **Skip:** `EntryType`, `DependencyType` — used internally by analysis layer.

#### `src/unfamiliar/models/` — Pydantic domain models
⏱️ 3 min | 3 files

- **`campaign.py`** — `Campaign` (repo_path, status, theme, mode) and `Briefing` (summary, tech_stack JSON, security_posture). These are the top-level entities.
- **`mission.py`** — `Mission` (title, category, difficulty, status, instructions, file_refs) plus junction models (`MissionFileRef`, `MissionPrerequisite`, `ModuleMissionLink`, `ChainMissionLink`). The prerequisite graph is what drives mission unlocking.
- **`analysis.py`** — `Module` (name, file paths, category_relevance JSON) and `FileSnapshot` (file_path, file_hash). Modules are clusters of related files.
- **What to notice:** All models have `id: int | None = None` — None before DB insert, int after. JSON columns store lists as serialized strings.

#### `src/unfamiliar/db/schema.py` — Database DDL
⏱️ 3 min

- **Purpose:** Complete SQLite schema — 11 tables with indexes.
- **What to notice:** WAL mode for concurrent reads. Foreign keys with CASCADE deletes. JSON columns for list fields. No ORM — raw SQL with parameterized queries.
- **Key tables:** `campaign`, `briefing`, `module`, `mission`, `mission_prerequisite` (DAG edges), `mission_chain`, `chain_mission` (ordered chain membership).

### Level 2: Data Flow (~10 min)

**Now trace how data moves** from a git repo to a TUI session.

#### `src/unfamiliar/config.py` — Configuration and campaign dirs
⏱️ 2 min | 316 lines

- **Purpose:** Loads `~/.unfamiliar/config.toml`, resolves API keys from env vars, computes campaign directory paths.
- **Key concepts:**
  - `UnfamiliarConfig` — Pydantic model with provider, token_budget, theme, and LLM overrides
  - `resolve_api_key()` — 3-tier lookup: config env override → provider-specific env var → generic `UNFAMILIAR_API_KEY`
  - `get_campaign_dir()` — deterministic path: `~/.unfamiliar/campaigns/<name>-<hash>/` with collision handling
- **What to notice:** No API keys in config files — env vars only (security decision from Phase 8.5). Campaign dirs use SHA-256 hash of absolute repo path for uniqueness.

#### `src/unfamiliar/campaign/orchestrator.py` — The glue layer
⏱️ 3 min | 308 lines

- **Purpose:** `create_campaign()` is the main entry point that ties everything together.
- **Data flow:** `analyze_repository()` → `create_chat_model()` → `generate_briefing()` → `persist_briefing_data()` → `run_mission_pipeline()` → `persist_pipeline_data()` → campaign ACTIVE
- **What to notice:** Progress callbacks for CLI status updates. `CampaignExistsError` triggers overwrite confirmation in CLI. Partial failure leaves campaign INITIALIZING (resumable). `resume_campaign()` scans all campaign dirs to find the most recent ACTIVE one.

#### `src/unfamiliar/db/connection.py` + `src/unfamiliar/db/__init__.py` — Database access
⏱️ 2 min

- **Purpose:** `open_campaign_db()` opens a SQLite connection and returns a `CampaignDB` (named tuple of all repositories).
- **What to notice:** Auto-creates schema on first open. Writes a `.repo_path` marker file for campaign-to-repo matching. Uses context manager for connection lifecycle.

#### `src/unfamiliar/db/repositories/` — Repository layer
⏱️ 3 min | 7 files

- **Purpose:** CRUD operations for each entity. No ORM — parameterized SQL.
- **Key files:**
  - `campaign.py` — `get_by_repo_path()`, `update_status()`, `delete()` (cascade)
  - `mission.py` — `get_by_campaign()`, `update_status()`, `count_completed()`, `count_by_campaign()`
  - `chain.py` — `get_by_campaign()`, `create_many()` with bulk insert
  - `mission_file_ref.py` — `get_dependents()`, `get_prerequisites()` — the prerequisite graph queries
- **What to notice:** `create_many()` uses `executemany()` then re-fetches by unique field — fragile if duplicates exist (documented in decisions.md). All repos take a `sqlite3.Connection` in constructor.

### Level 3: Application Logic (~12 min)

**Now read how the core features work.**

#### `src/unfamiliar/analysis/orchestrator.py` — Static analysis pipeline
⏱️ 3 min

- **Purpose:** `analyze_repository()` runs the 6-stage analysis pipeline.
- **Pipeline stages:** File discovery (git ls-files) → Parsing (language adapters) → Import graph → Module detection (label propagation) → Test detection → File scoring
- **What to notice:** Returns `AnalysisResult` — a flat container of all analysis outputs. No LLM calls here — pure static analysis. Adapters are registered by language.
- **Optional deep dive:** `analysis/scoring.py` for the priority scoring algorithm (entry points=100, centrality=50, complexity=30, tests=20).

#### `src/unfamiliar/analysis/adapters/` — Language adapters
⏱️ 2 min

- **Purpose:** Parse source files for imports, definitions, entry points per language.
- **Python** (`python_adapter.py`): Uses stdlib `ast` — no external deps.
- **JavaScript/TypeScript** (`javascript_adapter.py`, `typescript_adapter.py`): Uses tree-sitter. Shared utilities in `_treesitter_utils.py`, `_ts_imports.py`, `_ts_definitions.py`, `_ts_entry_points.py`.
- **What to notice:** All adapters implement `LanguageAdapter` protocol from `protocol.py`. `AdapterRegistry` dispatches by file extension.

#### `src/unfamiliar/llm/` — LLM integration
⏱️ 4 min | 10+ files

- **Provider factory** (`providers/factory.py`): Config-driven model creation via `init_chat_model()`. Supports Anthropic, GLM, OpenAI-compatible providers. Provider registry pattern with per-provider defaults.
- **Context builder** (`context.py`): Transforms `AnalysisResult` → LLM-ready text string within token budget. Dynamic budget allocation — modules/tests/security first, file contents get remaining budget.
- **Briefing** (`briefing/`): Single LLM call → `BriefingResponse` via structured output. Retry with exponential backoff.
- **Missions** (`missions/`): Multi-call pipeline — one LLM call per investigation category. `pipeline.py` orchestrates with LangGraph checkpointing. `validation.py` post-processes LLM output (clamp line numbers, break cycles, verify file paths). `structured.py` handles JSON truncation recovery.
- **What to notice:** The mission pipeline is the most complex part. Each category is an independent LLM call, checkpointed. Truncation recovery reconstructs partial JSON from incomplete API responses. Validation is entirely programmatic — no LLM calls.

#### `src/unfamiliar/campaign/missions.py` — Mission lifecycle engine
⏱️ 3 min | 283 lines

- **Purpose:** Status transitions and prerequisite cascading.
- **Key functions:**
  - `complete_mission()` — AVAILABLE/IN_PROGRESS → COMPLETED, then cascades to unlock dependents
  - `start_mission()` — AVAILABLE → IN_PROGRESS
  - `unlock_mission()` — force LOCKED → AVAILABLE (escape hatch)
  - `reopen_campaign()` — CLOSED → ACTIVE
  - `_unlock_eligible_dependents()` — checks all dependents' prerequisites, unlocks those fully satisfied
- **What to notice:** Status transitions are validated — can't complete a LOCKED mission, can't unlock COMPLETED. Detailed DEBUG logging added in Phase 20 for troubleshooting unlock cascades.

### Level 4: User Interface (~10 min)

#### `src/unfamiliar/cli.py` — CLI entry points
⏱️ 2 min | 384 lines

- **Purpose:** Typer CLI with 6 commands: `investigate`, `campaigns`, `resume`, `reopen`, `reconnect`, `upgrade`.
- **What to notice:** `investigate` orchestrates the full flow (create campaign → launch TUI). `resume` finds the most recent ACTIVE campaign. `reconnect` and `upgrade` are placeholders for v1.1. `_launch_tui()` is a deferred import to avoid loading Textual until needed.

#### `src/unfamiliar/tui/commands.py` — Command router
⏱️ 2 min | 197 lines

- **Purpose:** Parse user input → canonical command + args. Resolves themed aliases.
- **What to notice:** Multi-word alias resolution ("file report" → "complete", "break in" → "unlock"). Longest-match-first prevents "file" from matching before "file report". Case-insensitive. Unknown commands return `("unknown", [raw_input])`.

#### `src/unfamiliar/tui/themes/` — Theme system
⏱️ 2 min

- **Purpose:** `ThemeConfig` dataclass bundles CSS path, aliases, vocabulary, narrative config, colors, decorations, icons. Registry pattern with `get_theme()` / `register_theme()`.
- **Film Noir theme** (`film_noir/theme.py`): Defines all aliases ("investigate", "file report", "dossier", "the brief"), vocabulary ("lead" for mission, "case thread" for chain), and narrative style for LLM prompts.
- **What to notice:** `vocab()` and `alias()` methods with safe fallback to key. `NarrativeConfig` is injected into LLM mission prompts — the theme influences generated content, not just display.

#### `src/unfamiliar/tui/app.py` — Main TUI application
⏱️ 2 min (skim)

- **Purpose:** Textual `App` subclass. Composes header, content area, command reference, and input widgets. Dispatches commands from router to handler methods.
- **Key concepts:** Mission list cache for number-based selection. `on_mount` shows welcome or resume state. `ConfirmModal` for quit/end-campaign confirmations. Toast notifications for status changes.
- **What to notice:** Theme CSS loaded dynamically. Database opened in `on_mount`, closed in `on_unmount`. All user-facing text goes through `theme.vocab()` and `theme.alias()`.

#### `src/unfamiliar/tui/widgets/` + `src/unfamiliar/tui/queries.py` + `src/unfamiliar/tui/views.py`
⏱️ 2 min (skim)

- **Widgets:** `InvestigationHeader` (progress bar), `ContentArea` (main display with `show_*` methods), `CommandReference` (side panel), `CommandInput` (bottom input).
- **Queries:** Bridge between DB repositories and view data models. Pure functions: `load_header_data()`, `load_status_data()`, `load_available_missions()`, `load_mission_detail()`, etc.
- **Views:** Frozen dataclasses for UI data. No DB or Textual dependencies — clean data boundary.

### Level 5: Supporting Systems (~5 min)

#### `src/unfamiliar/analysis/security/` — Secret and vulnerability detection
⏱️ 1 min

- **`secrets.py`** — wraps `detect-secrets` for finding hardcoded secrets. Reports locations only, never captures values.
- **`vulnerabilities.py`** — wraps `pip-audit` for CVE scanning of Python dependencies.

#### `src/unfamiliar/analysis/filters/` — Discovery filtering
⏱️ 1 min

- **`gitignore.py`** — pathspec-based gitignore filtering
- **`patterns.py`** — exclude non-code files (images, fonts, binaries, lock files) before analysis. Reduces noise from 135 files to ~53 code files on typical repos.

#### `src/unfamiliar/analysis/graph/` — Import graph and clustering
⏱️ 2 min

- **`import_graph.py`** — Builds directed import graph, computes in-degree centrality, finds hub files.
- **`clustering.py`** — Label propagation algorithm for detecting logical modules. Works best on codebases with strong internal imports. Sparse graphs produce many singletons (documented limitation).

#### `src/unfamiliar/campaign/` — Campaign lifecycle
⏱️ 1 min

- **`discovery.py`** — Scans `~/.unfamiliar/campaigns/` to find all campaigns.
- **`persister.py`** — Persists briefing and pipeline data to SQLite. Handles module-mission linking.
- **`progress.py`** — Aggregates progress per category for status display.
- **`types.py`** — Shared types: `CompletionResult`, `CampaignExistsError`, `PersistResult`.

---

## 4. Testing Guide

⏱️ ~10 minutes

### Automated Tests

**Run the full suite:**
```bash
pytest tests/ -v
```
- [x] Expected: **1059 tests passing**, 0 failures
- [x] Run time: ~30-60 seconds

**Run by area:**
```bash
# Data layer
pytest tests/test_models.py tests/test_repositories.py tests/test_db_connection.py -v

# Static analysis
pytest tests/test_discovery.py tests/test_scoring.py tests/test_adapters.py tests/test_orchestrator.py tests/test_clustering.py tests/test_import_graph.py tests/test_security.py -v

# LLM pipeline
pytest tests/test_llm_briefing.py tests/test_llm_context.py tests/test_llm_provider.py tests/test_mission_generator.py tests/test_mission_pipeline.py tests/test_mission_validation_prereqs.py tests/test_mission_validation_filerefs.py tests/test_llm_structured.py -v

# Campaign and CLI
pytest tests/test_campaign_orchestrator.py tests/test_campaign_missions.py tests/test_campaign_discovery.py tests/test_campaign_progress.py tests/test_campaign_persister.py tests/test_cli.py -v

# TUI and theme
pytest tests/test_command_router.py tests/test_tui_queries.py tests/test_theme_config.py tests/test_theme_prompts.py -v

# Polish (Phase 20)
pytest tests/test_phase20_functions.py -v
```

**Coverage:**
```bash
pytest tests/ --cov=src/unfamiliar --cov-report=term-missing
```
- [x] Expected: ≥80% branch coverage across core modules

**What the tests validate:**
- Model serialization/deserialization round-trips
- Repository CRUD operations with real SQLite (no mocks)
- Analysis pipeline stages individually and end-to-end
- LLM provider creation with mocked API responses
- Mission validation (file path clamping, cycle detection, prerequisite graphs)
- Command routing with themed aliases
- Campaign lifecycle transitions
- Theme config accessors and fallbacks

**How to add tests:**
- Add to existing `tests/test_<module>.py` files
- Follow pattern: arrange (fixtures) → act (call function) → assert (check result)
- Use `conftest.py` fixtures for shared test data (campaigns, missions, etc.)
- LLM tests use `unittest.mock` — patch the prompt's `__or__` operator, not the model

### Manual Testing

**End-to-end with real LLM:**
1. Pick a small-medium open source repo (50-200 files, Python or JS/TS)
2. Run `unfamiliar investigate <repo>`
3. Work through 3-5 missions across different categories
4. Check that file references in missions point to real files
5. Verify prerequisite unlocking works (complete a root mission, check if dependents unlock)
6. Close the campaign, reopen it, verify progress preserved

**TUI-specific testing:**
1. Launch TUI and try every command alias from the Film Noir theme
2. Test edge cases: empty input, unknown commands, numbers out of range
3. Resize terminal window — layout should adapt
4. Test quit confirmation with mission in progress

---

## 5. Known Issues

### 🔴 Unimplemented Features

- **`reconnect` command** — placeholder only. Prints a message but doesn't actually re-link orphaned campaigns.
- **`upgrade` command** — no-op for v1.0. All campaigns use schema "1.0".
- **`notebook` command** — prints file path only (v1.1 feature).
- **Character archetypes** — `CharacterArchetype` enum defined but unused. Mission ordering is fixed in MVP.
- **Assessment mode** — `CampaignMode.ASSESSMENT` defined but not implemented.
- **Annotation/field report completion** — `CompletionMethod.ANNOTATION` and `FIELD_REPORT` defined, only `SELF_REPORT` used.

### 🟡 Known Limitations

- **Clustering quality on sparse repos** — Repos with few internal imports produce many singleton modules (files with no import connections form their own "module"). This is correct behavior but noisy. See decisions.md 2026-03-06.
- **Category hints are heuristic** — File categorization relies on naming conventions (`test_` → TESTING, `auth` → DOMAIN). Unconventional naming gets no hints. See decisions.md 2026-03-05.
- **`create_many()` fragility** — Bulk insert re-fetches by unique-ish field (path, title, name). Duplicate values within a campaign silently produce wrong ID assignment. No DB UNIQUE constraint enforces this.
- **Token budget enforcement** — Hard cap truncates context if total exceeds budget. Large repos may lose file contents section entirely. Budget only applies to analysis context, not LLM response tokens.
- **Mutmut + Hypothesis conflict** — Mutation testing fails on files with Hypothesis property-based tests due to `contextvars` collision. See decisions.md 2026-03-05.

### 🟠 Open Deferred Items (from `_planning/deferred.md`)

- **Modal keyboard navigation** — Arrow keys don't move button focus in confirmation modals. Tab works.
- **Command input refocus** — No keyboard shortcut to return focus to command input after Escape. Requires mouse click.
- **Duplicate thematic titles** — LLM occasionally generates identical themed mission titles. Deduplication added in Phase 20 but relies on title matching heuristics.
- **Spurious campaign directories** — Some repos get campaign dirs created in `~/.unfamiliar/campaigns/` without user explicitly investigating them. Needs investigation.
- **Themed language in TUI prompts** — Welcome/error messages still use some canonical names instead of themed aliases.
- **Mission count discrepancy** — Unlock notification sometimes doesn't fire when expected. DEBUG logging added but root cause not fully resolved.

### 🔵 Security Perception

- The app includes secret detection and CVE scanning as defensive analysis features.
- All analysis is local-only — no data leaves the user's machine.
- This should be documented clearly before public release to avoid "why is this tool scanning for secrets?" concerns.

---

## 6. Next Steps

### 🟢 Easiest (1-2 hours each)

1. **Implement `reconnect` command**
   - Complexity: Low
   - Impact: Fixes orphaned campaigns when repos move
   - Files: `cli.py`, `campaign/orchestrator.py`
   - Approach: Look up campaign by name/ID across all campaign dirs, update stored `repo_path` and `.repo_path` marker file

2. **Add `--skip-security` flag**
   - Complexity: Low
   - Impact: Addresses security perception concern, speeds up analysis
   - Files: `cli.py`, `analysis/orchestrator.py`
   - Approach: Add flag to `investigate` command, pass through to `analyze_repository()`, skip secrets/vulnerability steps

3. **Fix modal keyboard navigation**
   - Complexity: Low
   - Impact: Better accessibility for keyboard-only users
   - Files: `tui/screens/confirm.py`
   - Approach: Add Textual key bindings for arrow keys to cycle button focus

4. **Add command input refocus shortcut**
   - Complexity: Low
   - Impact: Quality-of-life for keyboard users
   - Files: `tui/app.py`
   - Approach: Add binding (e.g., `/` or `i`) that calls `self.query_one(CommandInput).focus()`

### 🟡 Medium (3-5 hours each)

5. **README and documentation for public release**
   - Complexity: Medium
   - Impact: Required for open source release
   - Files: `README.md` (new)
   - Approach: Installation, usage, supported languages, limitations, contributing guide. Emphasize local-only analysis.

6. **v1.1 completion methods (annotation + field report)**
   - Complexity: Medium
   - Impact: Richer learning feedback loop
   - Files: `campaign/missions.py`, `tui/app.py`, `tui/commands.py`
   - Approach: Add LLM call on completion for feedback. Annotation = user marks code regions. Field report = user writes summary.

7. **Investigate spurious campaign directories**
   - Complexity: Medium (investigation)
   - Impact: Prevents user confusion
   - Files: `config.py` (`get_campaign_dir` creates dirs), `campaign/orchestrator.py`
   - Approach: Audit all callers of `get_campaign_dir()` — it creates the parent `campaigns/` dir on every call. May need to separate "compute path" from "create directory".

8. **Add directory-based fallback clustering**
   - Complexity: Medium
   - Impact: Better module detection for sparse repos
   - Files: `analysis/graph/clustering.py`
   - Approach: For files with no import edges, group by directory. `backend/handlers/*.py` becomes one module even without imports.

### 🔴 Larger (8+ hours each)

9. **Notebook system (v1.1)**
   - Complexity: High
   - Impact: Major feature — persistent learning artifact
   - Files: New `notebook/` package
   - Approach: Markdown file per campaign. Auto-populated with mission completions, user annotations, key discoveries. Companion to the campaign.

10. **File staleness detection and refresh (v1.1)**
    - Complexity: High
    - Impact: Keeps missions relevant as code changes
    - Files: `analysis/`, `campaign/`, `llm/missions/`
    - Approach: Compare `FileSnapshot.file_hash` with current. Regenerate affected missions. Mark stale missions. Incremental re-analysis.

11. **Additional language adapters**
    - Complexity: High (per language)
    - Impact: Expands supported codebases
    - Files: `analysis/adapters/`
    - Approach: Implement `LanguageAdapter` protocol. Python is the reference implementation. JS/TS via tree-sitter is the multi-language reference. Go, Rust, Java are good candidates.

12. **Assessment mode (v1.1)**
    - Complexity: High
    - Impact: Different use case — structured code audit vs. onboarding
    - Files: `campaign/`, `llm/missions/`, `tui/`
    - Approach: Different completion criteria, scoring rubric, final report format.
