All persistent plugin data stays on your machine under ${CLAUDE_PLUGIN_DATA}.
When Claude Code does not provide that env var, claude-eta falls back to:
~/.claude/plugins/data/claude-eta-*if a runtime data directory already exists~/.claude/plugins/claude-eta/for local development
claude-eta stores multiple file types, not just one task history file.
| Path pattern | What it contains |
|---|---|
projects/<project_fp>/meta.json |
Project metadata: fingerprint, display name, cleartext cwd_realpath, repo size buckets, ETA accuracy counters |
projects/<project_fp>/sessions/<session_id>.json |
Session metadata: session id, display name, cleartext cwd_realpath, model, source, timestamps |
projects/<project_fp>/active/<session>__<agent>.json |
Active in-progress turn state, including counters, ETA cache, hashed per-file fingerprints, loop-detector fingerprints, and temporary last_assistant_message |
projects/<project_fp>/events/<session>__<agent>.jsonl |
Append-only event log for the turn lifecycle and tool activity |
projects/<project_fp>/completed/<session>__<agent>.jsonl |
Completed turns used for /eta, stats, insights, compare, and eval |
projects/<project_fp>/cache/ephemeral-<session>.json |
Last ETA snapshot and last completed-turn recap for the next prompt |
config/preferences.json |
Auto-ETA and community-sharing preferences |
community/.contributor_id |
Random local UUID used to derive contributor_hash |
community/_contribute_state.json |
Which work items were already contributed |
export/velocity-YYYY-MM.json |
Local anonymized export generated by /eta export |
local-salt.txt |
Per-machine salt used for local hashing |
Completed history is stored in completed/*.jsonl as one JSON object per turn.
The persisted CompletedTurn shape is:
turn_id
work_item_id
session_id
agent_key
agent_id
agent_type
runner_kind
project_fp
project_display_name
classification
prompt_summary
prompt_complexity
started_at
ended_at
wall_seconds
first_edit_offset_seconds
first_bash_offset_seconds
span_until_last_event_seconds
tail_after_last_event_seconds
active_seconds
wait_seconds
tool_calls
files_read
files_edited
files_created
unique_files
bash_calls
bash_failures
grep_calls
glob_calls
errors
model
source
stop_reason
repo_loc_bucket
repo_file_count_bucket
Notes:
prompt_summaryis only the first prompt line, truncated to 80 chars.active_secondsandwait_secondsare legacy compatibility aliases forspan_until_last_event_secondsandtail_after_last_event_seconds.- Completed turns do not store full prompt text, file contents, or raw code diffs.
Some data exists only while a turn is active or in the append-only event log.
active/*.json includes everything needed for live ETA refinement and loop detection, notably:
error_fingerprints: normalized loop-detector records shaped like{ fp, preview }path_fps: salted hashes of file paths touched during the active turncached_eta,live_remaining_p50,live_remaining_p80,live_phaselast_assistant_message: the latest assistant response while the turn is still active
last_assistant_message is local-only and is not copied into completed-turn history.
events/*.jsonl stores records like:
turn_startedtool_oktool_failturn_stoppedturn_stop_failureturn_replacedsession_endedsubagent_startedsubagent_stopped
Important privacy detail:
tool_failevents may store a rawerrorstring from the hook payload.- For Bash or test failures, that string can include stderr/stdout, filenames, stack traces, and code-adjacent snippets from local tooling output.
- This data stays local and is not uploaded by community features, but it is present on disk.
claude-eta does not intentionally persist:
- Full prompt bodies in completed task history
- File contents
- Diffs or patches
- Structured conversation history
- Cleartext per-file paths for file-operation counters in active/event data
Caveats:
- The project root realpath is stored locally in
meta.jsonandsessions/*.json. - Raw tool failure output can appear in
events/*.jsonl.
/eta inspect shows:
- Project fingerprint and display name
- Data directory
- Counts of tracked and completed turns
- Community-sharing status
- Project metadata when available
- The latest completed turn as raw JSON
- The latest local export file path
It does not currently dump:
events/*.jsonlactive/*.jsonsessions/*.json
If you want a full audit, inspect ${CLAUDE_PLUGIN_DATA} directly.
Community features are opt-in.
/eta compareis read-only. It fetches aggregate baselines and never uploads your local records./eta contributeis blocked until you explicitly run/eta community on./eta contributewithout--confirmpreviews what would be sent./eta contribute --confirmuploads only anonymized aggregate task records.
Community uploads use the AnonymizedRecord format:
{
"task_type": "bugfix",
"duration_seconds": 120,
"tool_calls": 15,
"files_read": 4,
"files_edited": 2,
"files_created": 0,
"errors": 1,
"model": "claude-sonnet-4-6",
"project_hash": "f4f7e7c2c3f1...",
"project_file_count": 184,
"project_loc_bucket": "small",
"plugin_version": "1.0.0",
"contributor_hash": "3e9c9f0c5e9b...",
"dedup_key": "67e4f0cc9c5d7c9f12b4d1e99c61b5a8",
"source_turn_count": 1,
"record_unit": "work_item"
}Meaning of the derived identifiers:
project_hash: one-way hash of the local project fingerprint using a machine-local saltcontributor_hash: one-way hash of a random UUID generated once on your machinededup_key: truncated SHA-256 ofcontributor_hash + ":" + work_item_id
What is not sent:
- Prompt text
- Completed-turn JSON
- Event logs
- Raw error strings
- File paths
- Project name
cwd_realpath- Code or file contents
The public community backend in this repo points to:
https://wviehmnmvvekiuxtxmmd.supabase.co
Verified from the code and SQL in this repository:
- Anon clients can
INSERTintovelocity_records - Anon clients can
SELECTfrombaselines_cache - Anon clients cannot read individual contributed rows through the shipped RLS policies
- A database trigger rate-limits contributions to 500 records/day per
contributor_hash - The committed Supabase anon key is intentional and public; it is not a secret
/eta compare also keeps a local cache at cache/baselines.json for 6 hours.
To use your own Supabase instance, set these environment variables:
CLAUDE_ETA_SUPABASE_URL— your Supabase project URLCLAUDE_ETA_SUPABASE_KEY— your anon key
The default key is intentionally public with restricted permissions (INSERT velocity_records, SELECT baselines_cache only).
It cannot read, update, or delete individual records.
Do not open public GitHub issues for suspected vulnerabilities.
Use GitHub private vulnerability reporting in the repository Security tab:
https://github.com/mmmprod/claude-eta/security
Include:
- a clear description of the issue and impact
- affected versions or commit SHAs if known
- reproduction steps or proof of concept
- any suggested remediation, if available