agents/skills/pi-sessions/SKILL.md
Find, list, and analyse pi agent sessions. Use when the user asks about past pi conversations, session history, costs, what pi did, reviewing a session, or debugging agent behaviour.
npx skillsauth add juanibiapina/dotfiles pi-sessionsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Pi stores conversation sessions as JSONL files. Each line is a JSON object with a type field.
~/.pi/agent/sessions/--<path>--/<timestamp>_<uuid>.jsonl
Directory names encode the working directory with / replaced by -.
Example: sessions for /Users/juan.ibiapina/workspace/juanibiapina/gmail-await live in:
~/.pi/agent/sessions/--Users-juan.ibiapina-workspace-juanibiapina-gmail-await--/
List all session directories (one per project):
ls ~/.pi/agent/sessions/
List sessions for a project (most recent last):
ls -t ~/.pi/agent/sessions/--<path>--/
Find sessions by date:
find ~/.pi/agent/sessions/ -name "2026-03-18*" -type f
Find sessions containing specific text:
grep -rl "search term" ~/.pi/agent/sessions/--<path>--/
Find the most recent session across all projects:
find ~/.pi/agent/sessions/ -name "*.jsonl" -type f -exec ls -t {} + | head -1
Each line has a type field. Records link via id/parentId forming a tree.
session (header, first line){"type":"session","version":3,"id":"uuid","timestamp":"...","cwd":"/path"}
message (conversation turns)Contains a message object with role:
user: User input. message.content is string or content blocks.assistant: Model response. Has message.content (array of text/thinking/toolCall blocks), message.model, message.provider, message.usage, message.stopReason.toolResult: Tool output. Has message.toolCallId, message.toolName, message.content, message.isError.model_change{"type":"model_change","provider":"anthropic","modelId":"claude-opus-4-6"}
thinking_level_change{"type":"thinking_level_change","thinkingLevel":"high"}
compactionContext was summarized to save tokens.
{"type":"compaction","summary":"...","tokensBefore":50000}
branch_summaryUser switched branches in the conversation tree.
custom_messageExtension-injected message (e.g., plan mode).
cat SESSION.jsonl | jq -r 'select(.type == "message") | .message.role' | sort | uniq -c
cat SESSION.jsonl | jq -r 'select(.type == "message" and .message.role == "user") | .message.content | if type == "string" then . else [.[] | select(.type == "text") | .text] | join("\n") end'
cat SESSION.jsonl | jq -r 'select(.type == "message" and .message.role == "assistant") | [.message.content[] | select(.type == "text") | .text] | join("\n") | select(length > 0)'
cat SESSION.jsonl | jq -r 'select(.type == "message" and .message.role == "assistant") | .message.content[] | select(.type == "toolCall") | .name' | sort | uniq -c | sort -rn
cat SESSION.jsonl | jq 'select(.type == "message" and .message.role == "assistant") | .message.content[] | select(.type == "toolCall") | {name, arguments}'
cat SESSION.jsonl | jq 'select(.type == "message" and .message.role == "toolResult" and .message.isError == true) | {toolName: .message.toolName, content: .message.content}'
cat SESSION.jsonl | jq -s '[.[] | select(.type == "message" and .message.role == "assistant") | .message.usage] | {turns: length, total_input: (map(.input) | add), total_output: (map(.output) | add), total_cache_read: (map(.cacheRead) | add), total_cache_write: (map(.cacheWrite) | add), total_cost: (map(.cost.total) | add)}'
cat SESSION.jsonl | jq -r 'select(.type == "message" and .message.role == "assistant") | .message.model' | sort | uniq -c
cat SESSION.jsonl | jq -r '.timestamp' | sed -n '1p;$p'
cat SESSION.jsonl | jq -r 'select(.type == "message") | "\(.timestamp) \(.message.role)" + (if .message.role == "assistant" then " [\(.message.stopReason)]" elif .message.role == "toolResult" then " [\(.message.toolName)]" else "" end)'
cat SESSION.jsonl | jq -r 'select(.type == "message" and .message.role == "assistant") | .message.content[] | select(.type == "toolCall" and .name == "bash") | .arguments.command'
cat SESSION.jsonl | jq -r 'select(.type == "message" and .message.role == "assistant") | .message.content[] | select(.type == "toolCall" and .name == "read") | .arguments.path'
cat SESSION.jsonl | jq -r 'select(.type == "message" and .message.role == "assistant") | .message.content[] | select(.type == "toolCall" and (.name == "write" or .name == "edit")) | "\(.name) \(.arguments.path)"'
development
My end-to-end development flow for any change. Use when fixing a bug, building a feature, or shipping any code change from understanding through production verification.
development
Creating plans. Use it for planning code changes.
tools
Send a message to another running pi session via its Unix socket. Use when the user wants to hand off context to another session, continue a conversation elsewhere, or notify another pi instance.
data-ai
Use when adding, installing, removing, or managing agent skills in this dotfiles repo. Triggers on "add skill", "install skill", "remove skill", "delete skill", "new skill", "manage skills", or any skill management task.