agent/skills/pi-logs/SKILL.md
Query pi agent session logs using Nushell's structured data pipeline. Use when debugging sessions, analyzing tool usage, finding commands run, or tracking file access patterns.
npx skillsauth add knoopx/pi pi-logsInstall 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.
Query pi agent session logs stored as JSON Lines (.jsonl) files in ~/.pi/agent/sessions/<project-path>/. Each line is a JSON object representing a session event.
def open-jsonl [file: path] {
open $file --raw | lines | each { from json }
}
# Load a single session
open-jsonl ~/.pi/agent/sessions/<project>/<session>.jsonl
# Load all sessions from a project
ls ~/.pi/agent/sessions/<project>/*.jsonl
| each { |f| open-jsonl $f.name } | flatten
Extract all tool calls from assistant messages:
# All tool calls with names and arguments
open-jsonl session.jsonl
| where type == "message" | where message.role == "assistant"
| get message.content | flatten
| where type == "toolCall" | select id name arguments
# Bash commands specifically
open-jsonl session.jsonl
| where type == "message" | where message.role == "assistant"
| get message.content | flatten
| where type == "toolCall" | where name == "bash"
| get arguments.command
# Files read
open-jsonl session.jsonl
| where type == "message" | where message.role == "assistant"
| get message.content | flatten
| where type == "toolCall" | where name == "read"
| get arguments.path
# Thinking content
open-jsonl session.jsonl
| where type == "message" | where message.role == "assistant"
| get message.content | flatten
| where type == "thinking" | get thinking
# All hook errors (eslint, typecheck failures)
open-jsonl session.jsonl | where type == "custom_message" | where customType == "hook-error"
| select timestamp content
# VCS notifications (jj squashes)
open-jsonl session.jsonl | where type == "custom_message"
| where customType | str starts-with "Squashed"
| select customType content timestamp
# Count events by type
open-jsonl session.jsonl | get type | uniq --count
# Count tool calls by type
open-jsonl session.jsonl
| where type == "message" | where message.role == "assistant"
| get message.content | flatten | where type == "toolCall"
| get name | uniq --count
# Token usage
open-jsonl session.jsonl
| where type == "message" | where message.role == "assistant"
| get message.usage | flatten | math sum
def "session-stats" [file: path] {
let data = (open-jsonl $file)
{
total_events: ($data | length),
messages: ($data | where type == "message" | length),
tool_calls: ($data | where type == "message" | where message.role == "assistant" | get message.content | flatten | where type == "toolCall" | length),
hook_errors: ($data | where type == "custom_message" | where customType == "hook-error" | length)
}
}
-- prefix/suffixmessage.content[] with type == "toolCall"flatten to extract nested arrays from message.contenttools
Inform the user what is happening — skip passive lookups
development
Renders markdown to self-contained HTML with a custom dark stylesheet and opens in browser. Use when previewing markdown documents, generating styled HTML from README or report files.
testing
Programmatic hunk selection for Jujutsu — split, commit, or squash specific hunks without interactive prompts. Use when making partial commits or selective squashes.
content-media
Manage version control with Jujutsu (jj) — no staging area, immediate changes, smart rebasing. Use when navigating history, squashing, or pushing to Git remotes.