Skip to content

Instantly share code, notes, and snippets.

@grahama1970
Last active August 27, 2025 22:26
Show Gist options
  • Select an option

  • Save grahama1970/66aa97de3c3e8e7c5fdd3b7f711958c1 to your computer and use it in GitHub Desktop.

Select an option

Save grahama1970/66aa97de3c3e8e7c5fdd3b7f711958c1 to your computer and use it in GitHub Desktop.
Codexer: shell helper for codex that pipes a startup checklist plus the last Codex conversation into codex. Supports --resume, --limit, --id, --index, and --list. Finds session JSONL under ~/.codex/sessions, orders by timestamp, prints User/Assistant lines.
# --- Place below in .zshrc ---------
# === Self-contained codexer with resume seed builder ===
# --- codexer: simple conversation loader for the Codex CLI --------------------
# Features:
# --resume Append the last conversation (user + assistant) to the seed
# --limit N Include only the last N lines of that conversation
# --id SESSION_ID Resume a specific session id (instead of the most recent)
# --index N Resume the Nth most-recent session id (1 = newest)
# --list [N] List the N most-recent session ids (default 20) and exit
#
# Behavior:
# - By default, loads the *entire* last conversation (Claude-like).
# - Falls back gracefully if jq or logs are missing.
# - All other args are passed through to the `codex` CLI.
# --- helpers ------------------------------------------------------------------
# Print recent unique session_ids from history.jsonl, newest first (one per line)
_codex_recent_session_ids() {
local history_file="$HOME/.codex/history.jsonl"
command -v jq >/dev/null 2>&1 || return 0
[[ -s "$history_file" ]] || return 0
if command -v tac >/dev/null 2>&1; then
# Reverse order after extracting IDs; unique while preserving order
jq -r '.session_id // empty' "$history_file" \
| tac | awk 'NF && !seen[$0]++'
else
# Portable reverse if tac unavailable
awk '{ buf[NR]=$0 } END { for (i=NR; i>0; i--) print buf[i] }' "$history_file" \
| jq -Rr 'fromjson? | .session_id // empty' \
| awk 'NF && !seen[$0]++'
fi
}
# Return the newest session file (.jsonl) under ~/.codex/sessions containing $1
_codex_find_session_file_for_id() {
local sid="$1" root="$HOME/.codex/sessions"
[[ -n "$sid" ]] || return 1
find "$root" -type f -name '*.jsonl' -print0 2>/dev/null \
| xargs -0 grep -l -- "$sid" 2>/dev/null \
| sort | tail -n 1
}
# Emit a labeled transcript (User:/Assistant:) ordered by timestamp for a file
_codex_transcript_for_file() {
local file="$1"
[[ -f "$file" ]] || return 1
jq -r '
select(.type=="message" and (.role=="user" or .role=="assistant")) as $m
| [ ($m.timestamp // $m.ts // 0)
, $m.role
, ( ($m.content[]? | select(.text? and (.text|type=="string")) | .text)
// ($m.text // "") )
]
| @tsv
' "$file" \
| sort -n \
| awk -F'\t' '{
role=$2; text=$3; gsub("\r","",text);
if (role=="user") print "User: " text;
else if (role=="assistant") print "Assistant: " text;
}'
}
# --- main ---------------------------------------------------------------------
codexer() {
emulate -L zsh
setopt pipefail
# Flags we handle; everything else is passed to codex
local resume=0 limit="" id="" index=""
local list=0 list_count=20
local -a passthrough=()
while [[ $# -gt 0 ]]; do
case "$1" in
--resume) resume=1 ;;
--limit) shift; limit="${1:-}" ;;
--id) shift; id="${1:-}" ;;
--index) shift; index="${1:-}" ;;
--list) list=1; if [[ -n "${2:-}" && "$2" == <-> ]]; then list_count="$2"; shift; fi ;;
--) shift; while [[ $# -gt 0 ]]; do passthrough+=("$1"); shift; done; break ;;
*) passthrough+=("$1") ;;
esac
shift || true
done
# Quick list mode
if (( list )); then
local n=0
_codex_recent_session_ids | while IFS= read -r sid; do
(( ++n ))
printf "%2d. %s\n" "$n" "$sid"
[[ $n -ge $list_count ]] && break
done
return 0
fi
# Default startup seed (your checklist)
local seed=$'1. Run '\''source .venv/bin/activate && set -a && [ -f .env ] && source .env'\''\n2. Activate the current dir as project using serena.\n3. Peruse the README.md and the pyproject.toml.'
# Optionally append last session transcript
if (( resume )); then
if ! command -v jq >/dev/null 2>&1; then
print -u2 -- "Warning: jq not found; skipping --resume."
else
# Decide which session_id to use
local sid="$id"
if [[ -z "$sid" ]]; then
if [[ -n "$index" && "$index" == <-> ]]; then
sid=$(_codex_recent_session_ids | sed -n "${index}p")
else
sid=$(_codex_recent_session_ids | head -n 1)
fi
fi
if [[ -z "$sid" ]]; then
print -u2 -- "No previous session_id found; skipping --resume."
else
local file; file=$(_codex_find_session_file_for_id "$sid")
if [[ -z "$file" ]]; then
print -u2 -- "No session file found for session_id=$sid."
else
local transcript; transcript=$(_codex_transcript_for_file "$file")
if [[ -n "$limit" && -n "$transcript" ]]; then
transcript=$(printf "%s\n" "$transcript" | tail -n "$limit")
fi
if [[ -n "$transcript" ]]; then
seed+=$'\n\n=== Last Session Transcript ===\n'"$transcript"
else
print -u2 -- "No user/assistant messages found in: $file"
fi
fi
fi
fi
fi
# Pipe seed into codex (stdin). Add your usual codex flags to $passthrough.
printf "%b\n" "$seed" | codex - "${passthrough[@]}"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment