## 1. Project Setup

- [x] 1.1 Initialize Python project with `uv init`, set name to `cc-logger` in `pyproject.toml`, configure as a CLI package with `[project.scripts]` entry `cc-logger = "cc_logger.cli:main"`
- [x] 1.2 Add dependencies with `uv add`: `click` for CLI, `pydantic` for data models
- [x] 1.3 Create source directory structure: `src/cc_logger/` with `__init__.py`, `cli.py`, `types/`, `discovery/`, `parser/`, `mapper/`

## 2. Pydantic Models

- [x] 2.1 Define CC JSONL message models in `src/cc_logger/types/cc.py`: `CCMessage` base with `type` discriminator, `CCUserMessage`, `CCAssistantMessage`, `CCSystemMessage`, content block types (`ThinkingBlock`, `TextBlock`, `ToolUseBlock`), `CCUsage` model — use lenient parsing (extra fields allowed, optional fields defaulting to None)
- [x] 2.2 Define ATIF output models in `src/cc_logger/types/atif.py`: `ATIFTrajectory`, `ATIFStep`, `ATIFAgent`, `ATIFToolCall`, `ATIFObservation`, `ATIFObservationResult`, `ATIFMetrics`, `ATIFFinalMetrics`, `SubagentTrajectoryRef` — with `model_dump(exclude_none=True)` for clean JSON output
- [x] 2.3 Define internal types in `src/cc_logger/types/session.py`: `SessionInfo` (from sessions-index.json entries), `ProjectInfo`, `SubagentInfo` dataclasses

## 3. Session Discovery

- [x] 3.1 Implement `scan_projects()` in `src/cc_logger/discovery/projects.py`: scan `~/.claude/projects/` for project directories, parse `sessions-index.json` in each, fall back to JSONL file scanning when index is missing or corrupted
- [x] 3.2 Implement `discover_subagents()` in `src/cc_logger/discovery/subagents.py`: given a session ID and project directory, glob `<session-id>/subagents/agent-*.jsonl` and return agent IDs + file paths
- [x] 3.3 Implement session filtering in `src/cc_logger/discovery/filters.py`: `filter_by_project()` (exact + substring match on `originalPath`), `filter_by_date()` (since date on modification time), `filter_by_session_id()` (exact UUID match)

## 4. JSONL Parser

- [x] 4.1 Implement streaming JSONL reader in `src/cc_logger/parser/jsonl_reader.py`: read file line-by-line, parse each line as JSON, skip malformed lines with warning, yield typed message dicts
- [x] 4.2 Implement conversation tree builder in `src/cc_logger/parser/tree_builder.py`: build `uuid → message` dict from all lines, find root (`parentUuid is None`), walk the main thread following `isSidechain == False` children, return linear message sequence
- [x] 4.3 Implement assistant response reassembly in `src/cc_logger/parser/reassemble.py`: group consecutive assistant messages by `message["id"]`, treat `<synthetic>` model messages as standalone, combine content blocks (thinking, text, tool_use) into a single `ReassembledResponse` dataclass with usage from the last chunk
- [x] 4.4 Implement message classifier in `src/cc_logger/parser/classify.py`: distinguish external user messages (string content) from tool results (list with `tool_result` dicts), compaction summaries (`isCompactSummary: True`), and match tool results to originating assistant messages via `sourceToolAssistantUUID`

## 5. ATIF Mapper

- [x] 5.1 Implement step builder in `src/cc_logger/mapper/step_builder.py`: convert classified+reassembled messages to ATIF steps — user messages → user steps, reassembled responses → agent steps with `message`/`reasoning_content`/`tool_calls`/`model_name`, system events → system steps; assign sequential `step_id` starting from 1
- [x] 5.2 Implement observation attachment in `src/cc_logger/mapper/observations.py`: after building agent steps with tool_calls, match subsequent tool_result messages by `tool_use_id`, attach as `observation.results[]` with `source_call_id`; prefix error results with `"ERROR: "`
- [x] 5.3 Implement metrics mapper in `src/cc_logger/mapper/metrics.py`: map `usage["input_tokens"]` → `prompt_tokens`, `usage["output_tokens"]` → `completion_tokens`, `usage["cache_read_input_tokens"]` → `cached_tokens`; compute `final_metrics` by summing all per-step metrics
- [x] 5.4 Implement subagent ref linker in `src/cc_logger/mapper/subagents.py`: for `Task` tool_calls, match subagent JSONL files by agent ID from tool result, recursively export subagent as separate ATIF file, attach `subagent_trajectory_ref` with `session_id` and relative `trajectory_path`
- [x] 5.5 Implement trajectory assembler in `src/cc_logger/mapper/trajectory.py`: combine agent config (`name: "claude-code"`, version from first message, model from first non-synthetic assistant), steps list, and final_metrics into complete ATIF dict with `schema_version: "ATIF-v1.6"`, serialize with `model_dump(exclude_none=True)`

## 6. CLI Commands

- [x] 6.1 Implement main CLI entry point in `src/cc_logger/cli.py`: set up `click` group with name `cc-logger`, global `--claude-dir` option defaulting to `~/.claude`
- [x] 6.2 Implement `list` command: accept `--project` and `--since` options, call session discovery with filters, display results as a formatted table using `click.echo` (session ID truncated to 8 chars, project name, date, first prompt truncated to 60 chars, message count)
- [x] 6.3 Implement `export` command: accept output directory argument + `--project`, `--session`, `--since` options, discover sessions with filters, export each session through the parser→mapper pipeline, write ATIF JSON files to output directory with project grouping for batch exports
- [x] 6.4 Implement progress reporting: print `[N/total] Exported <session-id> (X steps)` for each session during batch export, print summary (file path, step count, token totals) for single session export
- [x] 6.5 Implement error handling: `sys.exit(1)` for unwritable output dir, `sys.exit(0)` with message for no matching sessions, continue on per-session failures with warnings and report count at end

## 7. Integration and Testing

- [x] 7.1 Create an end-to-end export test: pick a real CC session JSONL, run the full pipeline, validate the output JSON has correct `schema_version`, sequential `step_id`s, non-empty steps, valid `source` values on all steps, and tool_calls matched with observations
- [x] 7.2 Test streaming reassembly: create a fixture JSONL with multi-line assistant responses sharing the same `message["id"]`, verify they produce a single agent step with all content blocks
- [x] 7.3 Test conversation tree linearization: create a fixture with sidechain branches, verify only the main thread appears in the output
- [x] 7.4 Test subagent export: create a fixture session with a Task tool_call and a subagent JSONL, verify the subagent is exported as a separate file with `subagent_trajectory_ref` linking them
- [x] 7.5 Validate output against Harbor: install `harbor` package, run `harbor view` on an exported trajectory to confirm it renders correctly
