Skip to main content

Prompt History

Every prompt you have ever typed into Claude Code and Codex is already sitting on your disk. This reads it back.

PyPI Python License

pipx install prompt-history && prompt-history

Your browser opens. There is everything you have asked an AI to build, searchable, grouped, one click from your clipboard.

No dependencies. No account. No network. It never writes to your session files, it only reads them.


Why you want this

You spent six months writing prompts. Some of them were really good. You have no idea where any of them are.

They are in ~/.claude/projects and ~/.codex/sessions, buried in JSONL transcripts next to a few hundred megabytes of tool output and model replies. Technically readable. Practically gone.

This pulls out your half of the conversation and nothing else.

  • The prompt you wrote at 2am that finally fixed the build
  • That one perfect refactor instruction you want to reuse
  • Six months of how you actually talk to these tools, as a file you own

Get it

pipx install prompt-history     # recommended
uv tool install prompt-history  # or this
pip install prompt-history      # or the classic

Python 3.9 or newer. That is the entire dependency list.

For a regular pip installation, both commands are installed into your Python environment's scripts directory and work from any folder:

python -m pip install --upgrade prompt-history
prompt-history --port 8080
phist --port 8080

If your scripts directory is not on PATH, use python -m prompthistory --port 8080. For a user-wide isolated command, pipx install prompt-history is also supported.

Set the port with --port 8080, PROMPT_HISTORY_PORT=8080, or port = 8080 under [server] in your config. CLI flags take priority. The default is 7777; if busy, the app tries up to 19 following ports and prints the actual URL. Use --port 0 to let the OS select an available port, and --no-browser to start without opening a tab.


Use it

The browser UI

prompt-history

Search across everything, browse by tool then project then session, copy any prompt with one click, download the lot as a zip.

It binds to 127.0.0.1 and serves a single HTML file. Nothing is uploaded, because there is nothing to upload to.

The terminal, if you live there

prompt-history list                         # everything, newest first
prompt-history search postgres migration    # both words, anywhere
prompt-history stats                        # what you have, at a glance
prompt-history sessions                     # every session, newest first
prompt-history sources                      # where it looked and what it found

Some real ones:

# Your long prompts from this quarter, as Markdown
prompt-history export -f md --since 2026-07-01 --min-words 60 -o good-prompts.md

# Everything you ever said to Codex about auth
prompt-history search auth --tool codex --full

# One project, one archive
prompt-history export -f zip --project checkout-api -o checkout-prompts.zip

# Pipe it anywhere
prompt-history list --json | jq -r '.[] | select(.words > 100) | .text'

--tool, --since, --until, --min-words, --max-words, --project, --exclude-project, --search and --no-slash-commands work on every command, including serve. Filter once, and the UI, the exports and the zip all agree.

The zip, organised

prompt-history export -f zip
prompt-history-2026-09-21/
├── README.txt                  what is in here, and the counts
├── index.json                  the full machine readable snapshot
├── prompts.csv                 one row per prompt, opens in any spreadsheet
├── prompts.md                  everything, one document
├── prompts.txt                 everything, no markup
├── by-session/
│   └── claude/checkout-api/
│       └── 2026-09-14-fix-the-stripe-webhook.md
└── by-date/
    └── 2026-09-14.md

by-session is the folder you actually read. Each file is one conversation, your prompts in the order you typed them, with the project, model and branch at the top.

Sync to a folder

Keep a plain folder of Markdown on disk, updated as you work. Obsidian vault, notes repo, wherever.

prompt-history sync ~/prompts --save
~/prompts/
├── claude/
│   ├── checkout-api/prompts.md
│   └── prompt-history/prompts.md
└── codex/
    └── infra/prompts.md

One file per project, every session inside it in the order you typed them. --save means it re-syncs automatically every time you scan, so the folder stays current without you thinking about it.

Change the shape however you like:

prompt-history sync ~/prompts --layout session    # a file per conversation
prompt-history sync ~/prompts --layout single     # everything in one file
prompt-history sync ~/notes --no-tool             # drop the tool folder
prompt-history sync ~/data --format json          # or txt, or csv
prompt-history sync ~/prompts --dry-run           # show me first

In the UI there is a Folder sync panel: pick a folder with a real system dialog, choose the structure, and watch the example path update as you change it.

Two things make it safe to point at a folder you care about:

  • A file is only rewritten when its content actually changed, and generated files carry no "synced at" stamp. Nothing churns, so it is fine to keep in git.
  • Sync keeps a manifest of exactly what it wrote. When cleaning up stale files, it will only delete things on that list. Your own notes in the same folder are never touched, and a folder with no manifest is never cleaned at all.

As a library

from prompthistory import PromptHistory

ph = PromptHistory(since="2026-01-01", tool="claude")

print(len(ph.prompts()))

for hit in ph.search("rate limit"):
    print(hit.timestamp, hit.project, hit.text[:80])

ph.write("q3.zip")                 # format inferred from the suffix
markdown = ph.render("md")         # or get it as a string

report = ph.sync("~/prompts")      # mirror to a folder
print(report.summary())            # "Wrote 3 new, 1 updated."

Every CLI flag is a keyword argument, and a typo raises instead of silently returning everything.

Prompt carries text, timestamp, project, session_id, model, git_branch, turn, words and kind. Session carries the prompts plus where they came from.


Configure it

prompt-history config --init     # writes a commented template
prompt-history config --show     # prints the values actually in effect

Lives at ~/.config/prompt-history/config.toml, or config.json if your Python is older than 3.11.

[sources]
claude_code = true
codex = true
include_subagents = false   # sub-agent prompts are written by the model, not you

[filter]
min_words = 5               # stop "yes", "continue" and "go on" from filling the UI
skip_slash_commands = true

[server]
port = 7777
open_browser = true

[sync]
sync_enabled = true         # mirror on every scan
sync_folder = "~/prompts"
sync_layout = "project"     # project | session | single
sync_include_tool = true    # tool/project/prompts.md, or project/prompts.md
sync_format = "md"

The UI writes its own sync choices to sync.json beside your config, so it never rewrites a file you hand edited.

Config file, then PROMPT_HISTORY_* environment variables, then CLI flags. Last one wins.


Where the prompts come from

Source Path What it gives
Claude Code transcripts ~/.claude/projects/<project>/<session>.jsonl Full text, timestamps, project, model, branch
Claude Code recent history ~/.claude.json Prompts whose transcript is gone
Codex rollouts ~/.codex/sessions/**/rollout-*.jsonl Full text and metadata
Codex composer history ~/.codex/history.jsonl Everything typed at the composer
Codex thread index ~/.codex/state*.sqlite Opening prompt of threads with no rollout file

CLAUDE_CONFIG_DIR and CODEX_HOME are respected, lists included. Windows %APPDATA% too.

Three Codex rollout formats are supported, current and legacy, because the on-disk shape has changed a few times.

Codex thread titles, projects, and sidebar sections are read from the local thread index when available. Internal approval-review and sub-agent sessions are excluded by default. A prompt you deliberately submit again is kept; duplicate transcript/event representations of the same submission are folded together.

Goal prompts stored as a goal-objective.md attachment are expanded back into their objective text. If only saved goal context survives, its objective is recovered once and labeled. Missing or unreadable files are reported alongside the original reference; they are never silently replaced with guessed text. Recovery reads local files only.

The browser renders Markdown links to files, tools, apps, and skills inline, and keeps attachment references below the prompt. Copy preserves the underlying Markdown. Local file and app links depend on your browser and installed application handlers; their targets remain visible on hover. No linked content is fetched automatically.

Thrown away: tool results, tool calls, assistant turns, compaction summaries, [Request interrupted] markers, sub-agent prompts, and injected context like <system-reminder>, <environment_context> and <user_instructions>. What is left is what you typed.

When a history log repeats a prompt a transcript already has, you see it once. stats tells you how many were folded together.


What it cannot do

Claude Desktop and ChatGPT Desktop chats are not files on your disk. They are in encrypted app storage or only on a server.

Codex makes this visible: if you use the desktop app, the thread titles are cached locally but the prompt text is not. Prompt History counts those threads and tells you, rather than quietly pretending they are not there.

If somebody tells you they can export your Claude Desktop history from local files, check what they are actually reading.


Privacy

Your prompts contain your API keys, your client names and your worst code. So:

  • Session files are opened read only and never modified
  • The server binds to loopback, and there is no outbound request anywhere in the codebase
  • No telemetry, no analytics, no update check
  • Zero third-party packages, so there is no supply chain to trust but this one

It is roughly 2,300 lines of stdlib Python plus one HTML file. Read it yourself, it will not take long.


Contributing

Adding a source is one file.

prompthistory/
├── api.py             PromptHistory: scan, filter, snapshot
├── config.py          file, env and flags, layered
├── model.py           Prompt, Session, text cleaning, timestamps
├── export.py          md, json, csv, txt, zip
├── server.py          loopback HTTP
├── cli.py             the commands
├── sources/
│   ├── claude_code.py
│   └── codex.py       <- copy this one
└── web/index.html     the whole frontend

Write a module in sources/ that returns list[Session], call it from PromptHistory.refresh(), add a fixture to tests/conftest.py. Done.

git clone https://github.com/alshell7/prompt-history
cd prompt-history
pip install -e ".[dev]"
pytest
node --test tests/web.test.cjs   # reference rendering and link safety

An optional browser smoke test lives in tests/browser_smoke.cjs. With Playwright and Chrome installed, run node tests/browser_smoke.cjs to check desktop/mobile rendering, copying, search, project isolation, and offline assets against synthetic data.

Cursor, Aider, Gemini CLI and Zed all keep local transcripts. Pull requests very welcome.


MIT. Interface icons from Tabler; Codex and Claude icons from Lobe Icons, bundled offline under MIT. See third-party notices.

Metadata

Release files for prompt-history 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for prompt-history 1.2.0
File Size Uploaded
prompt_history-1.2.0.tar.gz 73.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for prompt-history 1.2.0
File Interpreter ABI Platform
prompt_history-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 136.7 kB

Release files / prompt_history-1.2.0.tar.gz

Download URL prompt_history-1.2.0.tar.gz
Size 73.3 kB
Tags Source
SHA-256 checksum
How to use checksums
eeebed278daed93621ce33905faccaad51fea9f607343363483c07ca58765125
BLAKE2b-256 checksum
How to use checksums
af8a5e227aaa30493ededeecbd79574dd5adb6ffdda85dfb2e7c689316344a3e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / prompt_history-1.2.0-py3-none-any.whl

Download URL prompt_history-1.2.0-py3-none-any.whl
Size 63.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b5f2c347d6cc63dd7adc0eabb4c13e0d39341f2cb99ae04247812f966d4b0fa1
BLAKE2b-256 checksum
How to use checksums
ec647baeae181afd24d3be12a0ef3dcf08890d3eb5e68f7cb811a087622421eb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release history Release notifications | RSS feed

1.3.0

2 release files

This release

1.2.0 This release

2 release files

1.1.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page