# opensession-core
Core library, parsers, CLI, and TUI for the **HAIL** (Human AI Interaction Log) format.
## HAIL Specification (v1.0.0)
### Overview
HAIL is a line-delimited JSON (JSONL) format for recording AI coding sessions.
Every HAIL file has three sections: a header line, event lines, and a stats footer.
### JSONL Structure
```jsonl
{"type":"header", "version":"hail-1.0.0", "session_id":"...", "agent":{...}, "context":{...}}
{"type":"event", "event_id":"...", "timestamp":"...", "event_type":{...}, "content":{...}}
{"type":"event", "event_id":"...", "timestamp":"...", "event_type":{...}, "content":{...}}
{"type":"stats", "event_count":42, "message_count":10, ...}
```
### Session Fields
| `version` | `String` | `"hail-1.0.0"` |
| `session_id` | `String` | UUID |
| `agent` | `Agent` | AI agent information |
| `context` | `SessionContext` | Title, description, tags, timestamps, attributes |
| `events` | `Vec<Event>` | Flat timeline of events |
| `stats` | `Stats` | Aggregate statistics |
### Agent
| `provider` | `String` | `"anthropic"`, `"openai"`, `"google"`, etc. |
| `model` | `String` | `"claude-opus-4-6"`, `"gpt-4o"`, etc. |
| `tool` | `String` | `"claude-code"`, `"cursor"`, `"codex"`, etc. |
| `tool_version` | `Option<String>` | Tool version string |
### EventType — 22 variants
**Conversation**: `UserMessage`, `AgentMessage`, `SystemMessage`
**Reasoning**: `Thinking`
**Tool Calls**: `ToolCall{name}`, `ToolResult{name, is_error, call_id}`
**File Operations**: `FileRead{path}`, `FileEdit{path, diff}`, `FileCreate{path}`, `FileDelete{path}`
**Search**: `CodeSearch{query}`, `FileSearch{pattern}`, `WebSearch{query}`, `WebFetch{url}`
**Execution**: `ShellCommand{command, exit_code}`
**Media Generation**: `ImageGenerate{prompt}`, `VideoGenerate{prompt}`, `AudioGenerate{prompt}`
**Task Boundaries**: `TaskStart{title}`, `TaskEnd{summary}`
**Extension**: `Custom{kind}`
### ContentBlock — 8 types
`Text{text}`, `Code{code, language, start_line}`, `Image{url, alt, mime}`, `Video{url, mime}`, `Audio{url, mime}`, `File{path, content}`, `Json{data}`, `Reference{uri, media_type}`
### Stats
| `event_count` | `u64` |
| `message_count` | `u64` |
| `tool_call_count` | `u64` |
| `task_count` | `u64` |
| `duration_seconds` | `u64` |
| `total_input_tokens` | `u64` |
| `total_output_tokens` | `u64` |
| `user_message_count` | `u64` |
| `files_changed` | `u64` |
| `lines_added` | `u64` |
| `lines_removed` | `u64` |
## Supported Parsers
| Claude Code | `.jsonl` | `~/.claude/projects/` | ✅ |
| Codex | `.jsonl` | `~/.codex/sessions/` | ✅ |
| Cursor | `.vscdb` | `~/Library/Application Support/Cursor/` | ✅ |
| OpenCode | `.json` | `~/.local/share/opencode/storage/session/` | ✅ |
| Cline | `.json` | `~/.cline/data/tasks/` | ✅ |
| Amp | `.json` | `~/.local/share/amp/threads/` | ✅ |
| Gemini CLI | `.json`/`.jsonl` | `~/.gemini/tmp/*/chats/` | ✅ |
Source: `crates/parsers/src/`
## CLI — `opensession`
```
opensession discover # List all local AI sessions
opensession upload <file> # Upload a session file
opensession upload-all # Discover and upload all local sessions
opensession config [--server URL] [--api-key KEY] [--team-id ID]
opensession handoff [file] [-l|--last] [-o FILE] # Generate handoff summary
```
Configuration: `~/.config/opensession/config.toml`
## TUI — `opensession-tui`
### Mental Model
```
┌──────────────────────────────────────────────────────────────┐
│ opensession [BADGE] ViewMode N sessions daemon:pid │ ← Header
├──────────────────────────────────────────────────────────────┤
│ │
│ Session List ──Enter──▶ Session Detail │ ← Body
│ │ │ │
│ s Esc │
│ ▼ │
│ Settings / Setup │
│ │
├──────────────────────────────────────────────────────────────┤
│ j/k navigate Enter open / search Tab view q quit │ ← Footer
└──────────────────────────────────────────────────────────────┘
```
Connection badge reflects your setup:
- **[LOCAL]** gray — no server configured
- **[DOCKER]** blue — local/Docker server
- **[PERSONAL]** green — opensession.io personal
- **[TEAM: name]** purple — opensession.io team
### Session List Keybindings
| `j` / `↓` | Next session |
| `k` / `↑` | Previous session |
| `G` / `End` | Jump to last |
| `g` / `Home` | Jump to first |
| `Enter` / `l` / `→` | Open session detail |
| `/` | Search (title, tool, model, tags) |
| `Tab` | Cycle view: Local → Team → Repo(s) → Local |
| `p` | Publish session to server |
| `s` | Settings |
| `q` | Quit |
### Session Detail Keybindings
| `j` / `↓` | Next event |
| `k` / `↑` | Previous event |
| `G` / `End` | Last event |
| `g` / `Home` | First event |
| `Enter` / `Space` | Expand/collapse event content |
| `Tab` | Fold/unfold sub-agent task |
| `u` | Jump to next user message |
| `U` | Jump to previous user message |
| `1` | Filter: All |
| `2` | Filter: Messages |
| `3` | Filter: Tool calls |
| `4` | Filter: Thinking |
| `5` | Filter: File ops |
| `6` | Filter: Shell |
| `t` | Cycle task view: Chronological → Summary@Start → Summary@End |
| `c` | Toggle collapse consecutive similar events |
| `q` / `Esc` / `h` / `←` | Back to list |
### Local Storage
| `~/.local/share/opensession/local.db` | Session metadata cache (SQLite) |
| `~/.config/opensession/config.toml` | CLI config |
| `~/.config/opensession/daemon.toml` | Daemon config (server URL, API key, identity, watchers) |
## Workspace Crates
| `core` | HAIL types (`Session`, `Event`, `EventType`, `Content`) and JSONL serialization |
| `parsers` | 7 parser implementations + auto-discovery |
| `api-types` | Shared request/response types for client-server API |
| `local-db` | SQLite cache for session metadata + git context |
| `cli` | Command-line interface (clap) |
| `tui` | Terminal UI (ratatui + crossterm) |
## License
MIT