Skip to content

feat: add Pi session support (v2 subagent dirs + v3 native format)#155

Open
adamjramirez wants to merge 2 commits intoobsessiondb:mainfrom
adamjramirez:adamjramirez/pi-session-support
Open

feat: add Pi session support (v2 subagent dirs + v3 native format)#155
adamjramirez wants to merge 2 commits intoobsessiondb:mainfrom
adamjramirez:adamjramirez/pi-session-support

Conversation

@adamjramirez
Copy link

Summary

Adds support for pi sessions that were previously invisible to Rudel. Closes #153.

Before: 60 sessions visible (Claude Code only)
After: 1,188 sessions visible (Claude Code + Pi v2 + Pi v3)

Two Pi storage formats

Format Location Structure Count
Pi v2 ~/.claude/projects/<project>/<uuid>/subagents/agent-*.jsonl Same JSONL as Claude Code ~282
Pi v3 ~/.pi/agent/sessions/--<encoded-cwd>--/<timestamp>_<uuid>.jsonl Different schema (own event types, different usage field names) ~846

Approach

New PiAdapter following the existing adapter pattern (like Codex):

  • Registered via registerScanOnlyAdapter() — shares source: "claude_code" without colliding in the adapter registry. No SourceSchema changes needed.
  • v2 sessions: Reads subagent files, concatenates into content field, populates subagents map
  • v3 sessions: Transforms pi's native JSONL format into Claude Code-compatible JSONL so the ClickHouse materialized view can extract analytics (timestamps, tokens, model, errors, etc.)

v3 content transformation

The MV parses content line-by-line expecting Claude Code format (type: "user"/"assistant" at line level, message.usage.input_tokens, etc.). Pi v3 uses different structures, so the adapter transforms on upload:

  • {type: "message", message: {role: "user"}}{type: "user", ...}
  • Usage: inputinput_tokens, outputoutput_tokens, cacheReadcache_read_input_tokens, cacheWritecache_creation_input_tokens
  • Includes uuid and sessionId so the web UI conversation parser works
  • Strips v3-only fields (api, provider, stopReason, cost, totalTokens) to reduce content size
  • Skips non-interaction lines (session, compaction, thinking_level_change, toolResult)

Changes

File Change
packages/agent-adapters/src/adapters/pi/index.ts New — Pi adapter (v2 + v3 scanning, content transform)
packages/agent-adapters/src/registry.ts registerScanOnlyAdapter() for shared-source adapters
packages/agent-adapters/src/index.ts Export + register Pi adapter
apps/cli/src/lib/session-resolver.ts Resolve pi sessions by UUID or path (v2 dirs + v3 files)
apps/cli/src/commands/upload.ts Route to Pi adapter in all upload paths (interactive, single, retry)
apps/cli/src/commands/dev/list-sessions.ts Show [Pi] label for pi sessions
apps/cli/src/commands/enable.ts Handle Pi's no-op hooks gracefully
apps/cli/src/__tests__/agents.test.ts 24 tests covering v2 + v3 discovery, transform, upload

Zero API/schema/migration changes.

Tested

  • bun run check-types
  • bun run lint
  • bun test — 24 pass, 0 fail ✅
  • Real uploads of v2 and v3 sessions to app.rudel.ai — sessions appear with correct analytics, timestamps, conversation view ✅

Follow-up suggestion

Currently pi sessions show as source: "claude_code" since we reuse the existing source to avoid schema changes. A natural follow-up would be adding "pi" to SourceSchema so the UI can distinguish which harness produced a session.

Support pi (https://github.com/mariozechner/pi-coding-agent) sessions
that were previously invisible to Rudel. Handles two pi storage formats:

Pi v2 (~282 sessions): subagent-only UUID dirs under ~/.claude/projects/
Pi v3 (~846 sessions): native format under ~/.pi/agent/sessions/

Approach:
- New PiAdapter in packages/agent-adapters/src/adapters/pi/
- Registered via registerScanOnlyAdapter() to share source 'claude_code'
  without colliding in the adapter registry
- v3 content transformed to Claude Code JSONL format so the ClickHouse
  materialized view can extract analytics (timestamps, tokens, model, etc.)
- Session resolver updated to find pi sessions by UUID or path
- Upload command routes to Pi adapter via isPiSession() detection
- Enable command gracefully handles Pi's no-op hooks

Closes obsessiondb#153
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support pi (subagent-only) sessions — most sessions invisible to Rudel

1 participant