codex-session-history/skills/codex-session-history/SKILL.md
Query local Codex session history with jq. Use when users explicitly ask to search Codex sessions, inspect prior Codex conversations, find previous user messages, locate tool calls, summarize past work by working directory, or query Codex rollout JSONL files.
npx skillsauth add grailautomation/claude-plugins codex-session-historyInstall 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.
Use this skill when the user explicitly asks to inspect local Codex session history. Codex session files can contain private prompts, screenshots, tool outputs, and credentials accidentally pasted by a user, so extract only the fields needed to answer the request.
Codex stores active session JSONL files under date-partitioned directories:
~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl
Older sessions may be archived flat under:
~/.codex/archived_sessions/rollout-*.jsonl
Memory summaries under ~/.codex/memories/rollout_summaries/ are derived summaries, not raw session logs. Use them only when the user asks for memory-derived history or when raw session search is too broad.
Each line is a JSON object. Common top-level type values:
| Type | Useful fields | Notes |
| --- | --- | --- |
| session_meta | .payload.id, .payload.cwd, .payload.originator, .payload.cli_version, .payload.source, .payload.model_provider | Also may contain large instructions; do not print the full payload by default. |
| turn_context | .payload.turn_id, .payload.cwd, .payload.current_date, .payload.model, .payload.summary | Marks turn boundaries and compaction context. |
| event_msg | .payload.type, plus event-specific fields | Includes user_message, agent_message, task_started, task_complete, token_count, and patch events. |
| response_item | .payload.type, .payload.role, .payload.content, .payload.name, .payload.arguments | Stores model messages, reasoning, function calls, and tool outputs. |
Common response_item.payload.type values include message, reasoning, function_call, function_call_output, custom_tool_call, and custom_tool_call_output.
jq; avoid raw cat, head, or grep over full files.session_meta.payload.base_instructions, large image payloads, and full tool outputs unless the user explicitly needs them.--arg for user-provided search text instead of interpolating it into jq programs.Recent active sessions:
find "$HOME/.codex/sessions" -name '*.jsonl' -type f -print0 |
xargs -0 ls -t |
head -20
Recent active and archived sessions together:
find "$HOME/.codex/sessions" "$HOME/.codex/archived_sessions" \
-name '*.jsonl' -type f -print0 2>/dev/null |
xargs -0 ls -t |
head -30
Sessions for a working directory:
TARGET_CWD="$PWD"
find "$HOME/.codex/sessions" "$HOME/.codex/archived_sessions" \
-name '*.jsonl' -type f -print0 2>/dev/null |
while IFS= read -r -d '' f; do
jq -e --arg cwd "$TARGET_CWD" '
select(.type == "session_meta" and .payload.cwd == $cwd)
' "$f" >/dev/null 2>&1 && printf '%s\n' "$f"
done |
xargs ls -t 2>/dev/null |
head -20
Count top-level line types:
jq -r '.type // "<missing>"' "$SESSION_FILE" | sort | uniq -c
Count response item types:
jq -r '
select(.type == "response_item") |
.payload.type // "<missing>"
' "$SESSION_FILE" | sort | uniq -c
Show safe metadata:
jq -c '
select(.type == "session_meta") |
{
timestamp,
id: .payload.id,
cwd: .payload.cwd,
originator: .payload.originator,
cli_version: .payload.cli_version,
source: .payload.source,
model_provider: .payload.model_provider
}
' "$SESSION_FILE"
User messages from the event stream:
jq -r '
select(.type == "event_msg" and .payload.type == "user_message") |
.timestamp + " | " + (.payload.message // "" | gsub("\n"; " ") | .[0:300])
' "$SESSION_FILE"
Assistant final/intermediate messages from the event stream:
jq -r '
select(.type == "event_msg" and .payload.type == "agent_message") |
.timestamp + " | " + ((.payload.phase // "agent") + " | " + (.payload.message // "" | gsub("\n"; " ") | .[0:300]))
' "$SESSION_FILE"
Messages from response items:
jq -r '
def content_text:
if (.payload.content | type) == "array" then
[.payload.content[]? | .text // .input_text // empty] | join(" ")
elif (.payload.content | type) == "string" then
.payload.content
else
""
end;
select(.type == "response_item" and .payload.type == "message") |
.timestamp + " | " + (.payload.role // "unknown") + " | " + (content_text | gsub("\n"; " ") | .[0:300])
' "$SESSION_FILE"
Search user and assistant event messages across active and archived sessions:
QUERY="keyword"
find "$HOME/.codex/sessions" "$HOME/.codex/archived_sessions" \
-name '*.jsonl' -type f -print0 2>/dev/null |
while IFS= read -r -d '' f; do
jq -r --arg q "$QUERY" --arg file "$f" '
select(
.type == "event_msg" and
(.payload.type == "user_message" or .payload.type == "agent_message") and
((.payload.message // "") | test($q; "i"))
) |
$file + "\t" + .timestamp + "\t" + .payload.type + "\t" +
((.payload.message // "") | gsub("\n"; " ") | .[0:240])
' "$f" 2>/dev/null
done
Search response item text while avoiding session metadata:
QUERY="keyword"
jq -r --arg q "$QUERY" '
def content_text:
if (.payload.content | type) == "array" then
[.payload.content[]? | .text // .input_text // empty] | join(" ")
elif (.payload.content | type) == "string" then
.payload.content
else
""
end;
select(.type == "response_item" and .payload.type == "message") |
content_text as $text |
select($text | test($q; "i")) |
.timestamp + " | " + (.payload.role // "unknown") + " | " + ($text | gsub("\n"; " ") | .[0:240])
' "$SESSION_FILE"
List function calls without full arguments:
jq -r '
select(.type == "response_item" and .payload.type == "function_call") |
.timestamp + " | " + (.payload.name // "tool") + " | " + (.payload.call_id // "")
' "$SESSION_FILE"
Find calls to a specific tool:
TOOL_NAME="exec_command"
jq -r --arg tool "$TOOL_NAME" '
select(
.type == "response_item" and
.payload.type == "function_call" and
.payload.name == $tool
) |
.timestamp + " | " + (.payload.call_id // "") + " | " + ((.payload.arguments // "") | tostring | gsub("\n"; " ") | .[0:300])
' "$SESSION_FILE"
List tool outputs by call id without printing full output:
jq -r '
select(.type == "response_item" and .payload.type == "function_call_output") |
.timestamp + " | " + (.payload.call_id // "") + " | " + ((.payload.output // "") | tostring | gsub("\n"; " ") | .[0:220])
' "$SESSION_FILE"
When the user asks to find prior Codex work:
session_meta.payload.cwd.event_msg user and assistant messages first; use response_item for deeper reconstruction.documentation
Write a feature spec or PRD from a problem statement or feature idea
development
Synthesize qualitative and quantitative user research into structured insights and opportunity areas. Use when analyzing interview notes, survey responses, support tickets, or behavioral data to identify themes, build personas, or prioritize opportunities.
research
Synthesize user research from interviews, surveys, and feedback into structured insights
data-ai
Generate a stakeholder update tailored to audience and cadence