# PARSER Agent Instructions

You are the PARSER agent in a multi-agent analysis pipeline. Your job is to parse 34 Codex CLI session files and compute heuristic metrics on each.

## Paths

- **Repo root**: The current working directory (should be the trace repo)
- **Input sessions**: `docs/internal/2026/01/` (subdirs: 28, 29, 30, 31)
  - If this path doesn't exist, try `/home/sagar/trace/docs/internal/2026/`
- **Output dir**: `docs/run1-09022026/analysis-outputs/`
- **Parsed output**: `docs/run1-09022026/analysis-outputs/parsed/` (one JSON per session)
- **Metrics output**: `docs/run1-09022026/analysis-outputs/metrics.json`
- **Status file**: `docs/run1-09022026/analysis-outputs/coordination/parser.json`

## Status Protocol (CRITICAL)

You MUST write your status to the coordination file after EVERY significant step. The orchestrator polls this every 15 seconds to know when to launch downstream agents.

```json
{
  "status": "in_progress",
  "current_task": "parsing session rollout-2026-01-28T15-51-17",
  "completed_tasks": ["task1", "task2"],
  "sessions_parsed": 5,
  "sessions_total": 34,
  "errors": []
}
```

Set `"status": "completed"` only when ALL 34 sessions are parsed AND metrics.json is written.
Set `"status": "failed"` with `"error": "description"` if you hit an unrecoverable error.

## Step 1: Create directories

```bash
mkdir -p docs/run1-09022026/analysis-outputs/{coordination,parsed,deep_dive}
```

Write initial status: `{"status": "in_progress", "current_task": "starting parser", "completed_tasks": [], "sessions_parsed": 0, "sessions_total": 34, "errors": []}`

## Step 2: Parse all 34 JSONL files

For each `.jsonl` file in `docs/internal/2026/01/{28,29,30,31}/`:

Each line is a JSON object with this structure:
```json
{"timestamp": "...", "type": "session_meta|response_item|event_msg|turn_context", "payload": {...}}
```

Parse each file and extract a `ParsedSession` JSON with these fields:

```json
{
  "filename": "rollout-2026-01-28T15-51-17-019c054d-499a-7f32-bee4-5a701f1ce557.jsonl",
  "date": "2026-01-28",
  "session_id": "extracted from filename (the UUID part after the timestamp)",
  "first_timestamp": "ISO timestamp of first event",
  "last_timestamp": "ISO timestamp of last event",
  "duration_seconds": 123.4,
  "model": "from turn_context payload -> model field",
  "cli_version": "from session_meta payload -> cli_version",
  "approval_policy": "from turn_context payload -> approval_policy",
  "effort": "from turn_context payload -> effort",
  "raw_event_count": 62,
  "user_messages": [
    {"index": 0, "text": "full text of user prompt", "timestamp": "..."}
  ],
  "assistant_messages": [
    {"index": 0, "text": "full text of assistant response", "timestamp": "..."}
  ],
  "tool_calls": [
    {"name": "function_name", "input_summary": "brief summary of input", "output_summary": "brief of output"}
  ],
  "turn_count": 7,
  "files_touched": ["list of file paths from tool calls"],
  "summary_from_context": "the summary field from turn_context if present"
}
```

### How to extract messages from the JSONL:

- **type == "session_meta"**: Extract `payload.id`, `payload.cli_version`, `payload.cwd`
- **type == "turn_context"**: Extract `payload.model`, `payload.approval_policy`, `payload.effort`, `payload.summary`
- **type == "response_item"**: This is the main content.
  - `payload.role == "developer"` or `payload.role == "user"` → it's a user message. Extract text from `payload.content[]` where content items have `type: "input_text"` or `type: "text"`
  - `payload.role == "assistant"` → assistant message. Extract from `payload.content[]`
  - `payload.type == "function_call"` → tool call. Extract `payload.name`, `payload.arguments`
  - `payload.type == "function_call_output"` → tool result. Extract `payload.output`
- **type == "event_msg"**: Usually streaming deltas — skip these for the parsed summary, but count them for `raw_event_count`

### Important parsing notes:
- Content can be deeply nested. `response_item.payload` may have a `content` array where each item has a `type` and corresponding text field.
- Some messages have very long content (full file contents from reads). For `assistant_messages` and `user_messages`, keep the full text — the deep-dive agents need it.
- For `tool_calls`, summarize the input/output to ~200 chars max to keep file sizes manageable.
- `turn_count` = number of distinct user↔assistant exchanges (count user messages as a proxy).

Write each parsed session to: `docs/run1-09022026/analysis-outputs/parsed/{filename}.json`

Update your status file after every 5 sessions parsed.

## Step 3: Compute heuristic metrics

After all 34 are parsed, compute metrics for each session and write them into the parsed JSON (add a `"metrics"` field):

```json
{
  "metrics": {
    "outcome": "resolved|abandoned|partial|context-only",
    "session_type": "bug-fix|feature|exploration|setup|refactor|unknown",
    "iteration_count": 7,
    "struggle_score": 3,
    "prompt_specificity": 4,
    "time_of_day": "afternoon"
  }
}
```

### Outcome classification rules:
- `context-only`: raw_event_count <= 5 AND (no assistant messages OR only 1 short assistant message)
- `abandoned`: turn_count > 3 AND last message is from user (no final assistant response)
- `resolved`: last message is assistant AND (contains code/file writes OR user previously said words like "thanks", "done", "works", "perfect", "great")
- `partial`: everything else

### Session type classification (keyword match on ALL user messages, case-insensitive):
- `bug-fix`: "fix", "error", "crash", "fail", "bug", "broken", "issue", "traceback", "exception", stack trace patterns
- `feature`: "add", "implement", "create", "build", "new feature", "write"
- `exploration`: "how", "why", "explain", "what", "?", "help me understand"
- `setup`: "install", "configure", "setup", "init", "dependency", "pip", "npm", "config"
- `refactor`: "refactor", "clean", "optimize", "improve", "rename", "restructure"
- `unknown`: if no keywords match

### Prompt specificity (1-5):
- 1: Single vague sentence, no context (e.g. "how to improve my model?")
- 2: General question with some context
- 3: Specific question with error message OR file reference
- 4: Detailed request with error + file path + what they tried
- 5: Precise diagnosis with root cause, file paths, line numbers, and proposed fix

### Struggle score (0-10):
- +2 for each: turn_count > 10, turn_count > 20
- +2 if user messages contain repeated similar phrases (copy-paste of same error)
- +2 if session has "error" or "fail" keywords in multiple user messages
- +2 if outcome is "abandoned"
- +2 if duration > 600 seconds AND outcome != "resolved"

### Time of day:
- Parse first_timestamp, extract hour (UTC)
- morning: 6-12, afternoon: 12-18, evening: 18-24, night: 0-6

## Step 4: Write aggregated metrics.json

```json
{
  "total_sessions": 34,
  "by_outcome": {"resolved": 15, "abandoned": 5, "partial": 10, "context-only": 4},
  "by_type": {"bug-fix": 12, "feature": 8, "setup": 5, "exploration": 5, "refactor": 2, "unknown": 2},
  "avg_turns": 8.5,
  "avg_duration_seconds": 245.3,
  "avg_specificity": 3.2,
  "avg_struggle_score": 3.8,
  "by_date": {"2026-01-28": 7, "2026-01-29": 16, "2026-01-30": 3, "2026-01-31": 8},
  "by_time_of_day": {"morning": 10, "afternoon": 8, "evening": 12, "night": 4},
  "sessions": [
    {"filename": "...", "outcome": "...", "type": "...", "turns": 7, "duration": 108, "specificity": 3, "struggle": 2}
  ]
}
```

## Step 5: Final status

Update status to completed:
```json
{
  "status": "completed",
  "current_task": "done",
  "completed_tasks": ["directories_created", "34_sessions_parsed", "metrics_computed", "metrics_json_written"],
  "sessions_parsed": 34,
  "sessions_total": 34,
  "errors": []
}
```

## Constraints
- Use Python for parsing. You can write a script or do it inline.
- Do NOT use any external packages — only Python stdlib (json, pathlib, os, datetime, re, statistics, collections).
- Do NOT do git operations — the orchestrator handles git.
- Do NOT modify any files outside the output directory.
- If a JSONL line fails to parse, log the error and continue (don't crash on one bad line).
