Skip to content

Latest commit

 

History

History
241 lines (180 loc) · 7.44 KB

File metadata and controls

241 lines (180 loc) · 7.44 KB

Security & Privacy

Local storage

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:

  1. ~/.claude/plugins/data/claude-eta-* if a runtime data directory already exists
  2. ~/.claude/plugins/claude-eta/ for local development

What claude-eta stores locally

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 turn format

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_summary is only the first prompt line, truncated to 80 chars.
  • active_seconds and wait_seconds are legacy compatibility aliases for span_until_last_event_seconds and tail_after_last_event_seconds.
  • Completed turns do not store full prompt text, file contents, or raw code diffs.

Active-turn and event-log data

Some data exists only while a turn is active or in the append-only event log.

Active turn fields

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 turn
  • cached_eta, live_remaining_p50, live_remaining_p80, live_phase
  • last_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.

Event log fields

events/*.jsonl stores records like:

  • turn_started
  • tool_ok
  • tool_fail
  • turn_stopped
  • turn_stop_failure
  • turn_replaced
  • session_ended
  • subagent_started
  • subagent_stopped

Important privacy detail:

  • tool_fail events may store a raw error string 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.

What is not stored locally

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.json and sessions/*.json.
  • Raw tool failure output can appear in events/*.jsonl.

/eta inspect

/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/*.jsonl
  • active/*.json
  • sessions/*.json

If you want a full audit, inspect ${CLAUDE_PLUGIN_DATA} directly.

Community features

Community features are opt-in.

  • /eta compare is read-only. It fetches aggregate baselines and never uploads your local records.
  • /eta contribute is blocked until you explicitly run /eta community on.
  • /eta contribute without --confirm previews what would be sent.
  • /eta contribute --confirm uploads only anonymized aggregate task records.

What /eta contribute sends

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 salt
  • contributor_hash: one-way hash of a random UUID generated once on your machine
  • dedup_key: truncated SHA-256 of contributor_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

Community backend

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 INSERT into velocity_records
  • Anon clients can SELECT from baselines_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.

Self-hosting

To use your own Supabase instance, set these environment variables:

  • CLAUDE_ETA_SUPABASE_URL — your Supabase project URL
  • CLAUDE_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.

Reporting vulnerabilities

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