# Next Session: Paper-to-Notebook Kernel Agent — Execute Plan

## What to Do
Execute the approved plan at `~/.claude/plans/stateless-splashing-comet.md` — Paper-to-Notebook Kernel Agent for Annie with Jupyter server on Titan.

## Context (read these first)
1. `~/.claude/plans/stateless-splashing-comet.md` — Full plan (v2, post-adversarial review, 28 findings addressed)
2. `docs/RESEARCH-PAPER-TO-NOTEBOOK.md` — Research findings, stealable patterns, architecture decisions
3. MEMORY.md session 373 — Session summary

## Architecture Summary
User sends arXiv URL via Telegram → Annie's `convert_paper_to_notebook` tool dispatches to TaskQueue → Claude Code CLI (already integrated) downloads PDF, reads it (multimodal), generates .ipynb with 12-section PyTorch notebook → delivers via:
1. Telegram file attachment (.ipynb)
2. Jupyter URL on Titan (GPU-enabled, Docker-based)
3. HTML preview (nbconvert)

## Execution Order

### Phase 1: File Delivery Infrastructure
- Extend `services/annie-voice/task_delivery.py` — add file_path, file_name fields
- Extend `services/telegram-bot/pending_handler.py` — add `send_document()` with path validation [S9], retry-safe unlink [A7]
- Tests

### Phase 1.5: Jupyter Server on Titan (Docker-based)
- **CRITICAL**: System Python on Titan has CPU-only torch. GPU torch only in Docker (NGC image).
- Docker container: `nvcr.io/nvidia/pytorch:25.11-py3` with `pip install jupyter pandas`
- Port 8890, bind-mount `~/.her-os/annie/task_results/notebooks/`
- Dedicated `~/.her-os-jupyter-token` (NOT shared her-os-token) [J1, J6]
- Add `start_jupyter()` to start.sh, `stop_jupyter()` to stop.sh
- One-time: `scripts/setup-jupyter-tunnel.sh` for cloudflared route to `jupyter.her-os.app`

### Phase 2: Core Pipeline
- NEW: `services/annie-voice/paper_notebook.py` (~220 lines)
- Modify `services/annie-voice/claude_code_client.py` — add `allowed_tools` param [M11]
- Verify Claude CLI `--allowed-tools` format (comma or space separated?) [B5]
- Add "generation" budget tier to agent_context.py
- Tests

### Phase 3: Tool Integration
- Add tool schema to CLAUDE_TOOLS in text_llm.py
- Add dispatch in `_dispatch_tool()` — route through TaskQueue [A2]
- Add PaperNotebookAdapter to tool_adapters.py
- Fix imports: uuid, datetime [B2], fix _current_metadata [M10]
- Tests

### Phase 4: E2E Verification
- Local test, Telegram E2E, edge cases

## Critical Review Findings (MUST follow)
- **NO Bash** in Claude Code allowed_tools — PDF prompt injection risk [A5, S7]
- **SSRF protection** — validate redirect hostname is *.arxiv.org [S8]
- **Stream PDF download** — don't buffer 30MB in memory [P15]
- **Semaphore(2)** — max 2 concurrent Claude Code conversions [P16]
- **Retry-safe unlink** — only delete result JSON AFTER successful send_document [A7]
- **Path validation** — check file_path prefix in pending_handler [S9]
- **PDF cleanup in finally block** — not just success path [B3, P17]

## Files to Create/Modify
| File | Action |
|------|--------|
| `services/annie-voice/paper_notebook.py` | CREATE |
| `services/annie-voice/tests/test_paper_notebook.py` | CREATE |
| `scripts/setup-jupyter-tunnel.sh` | CREATE |
| `services/annie-voice/task_delivery.py` | MODIFY |
| `services/annie-voice/text_llm.py` | MODIFY |
| `services/annie-voice/tool_adapters.py` | MODIFY |
| `services/annie-voice/claude_code_client.py` | MODIFY |
| `services/annie-voice/agent_context.py` | MODIFY |
| `services/telegram-bot/pending_handler.py` | MODIFY |
| `start.sh` | MODIFY |
| `stop.sh` | MODIFY |
