Skip to content

Add PyPI metadata: readme, classifiers, project URLs - #3

Merged
anilmurty merged 1 commit into
mainfrom
update-pypi-metadata
Apr 6, 2026
Merged

Add PyPI metadata: readme, classifiers, project URLs#3
anilmurty merged 1 commit into
mainfrom
update-pypi-metadata

Conversation

@anilmurty

Copy link
Copy Markdown
Contributor

Summary

  • Add readme = "README.md" so PyPI renders the project description
  • Add authors, classifiers, and [project.urls] (Homepage, Repository, Issues)
  • Update description to "Local-first OTel-native observability for Autonomous AI agents"

PyPI will pick up these changes on the next release.

Test plan

  • python -m build succeeds
  • Next release shows README on PyPI project page

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@anilmurty
anilmurty merged commit 8ff9c04 into main Apr 6, 2026
4 checks passed
@anilmurty
anilmurty deleted the update-pypi-metadata branch April 6, 2026 22:29
anshss added a commit that referenced this pull request Apr 12, 2026
…dex migration

- Use cursor-local .description instead of connection-level to avoid
  race conditions with concurrent queries
- Fix get_traces() GROUP BY to aggregate per trace_id only; use subquery
  for name and error-aware CASE expression for status_code
- Add migration #3 to recreate missing performance indexes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
anilmurty added a commit that referenced this pull request Jun 19, 2026
…#10,#13)

Smoke-test playbook (tests/manual-new-release-tests.md):

- #3 (and #8/#9/#11/#12/#14/#16 — same root cause): code blocks are now
  command-only; the inline "# comments" and "# [ ]" checklists that the markdown
  copy button was pulling into copied commands moved to prose / "- [ ]" lists
  around each block. Added a note explaining the convention.
- #10: corrected the Section 4 trim expectation — with [capture] prompts=false
  (default), trim checks the capture prereq first and prints the capture hint,
  NOT the tokenjam[bloat] install hint (only reachable once capture is on).
- #13: export file is "claude-code-<date>.jsonc", not ".json".

Doc-only; no code changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
anilmurty added a commit that referenced this pull request Jun 19, 2026
docs: smoke-test playbook — command-only blocks + trim/jsonc fixes (#3, #10, #13)
anilmurty added a commit that referenced this pull request Jun 23, 2026
, #213) (#218)

* Add Lens cost charts: stacked by-model/agent + cache-savings time-series

Wave 1 of the Lens Visualizations milestone (#3). Two new cost charts on the
Cost screen, both server-shaped (the UI consumes the response + the framing
block, never re-deriving plan-tier rules).

#213 — Stacked cost-by-model / -by-agent over time. The /cost `series` already
grouped by (bucket, agent, model); it now also carries `provider` + the full
token-component split (cache read/write) so it's the reusable group-by shape the
future analytics explorer (#210) can pivot too. A new StackedBarChart renders
cumulative back-to-front uPlot bars (cheap, offline) for the model/agent toggle;
`total` keeps the line view. Plan-tier framing respected — subscription/local
stack token volume, not raw spend.

#212 — Cache-savings time-series. New GET /api/v1/cost/cache returns per-bucket
cache hit-rate (cache_read / (cache_read + input)) and the dollars already
*captured* by real cache reads, priced per (provider, model) as
cache_read_tokens × (input_rate − cache_read_rate) — a measured figure. The
window-level *estimated recoverable* comes from the cache analyzer's #111
contract. A new CacheSavingsChart draws cumulative captured (left axis) + hit-
rate (right axis) + a dashed "achievable" envelope (captured + recoverable).
Honesty discipline (Critical Rule 14): "captured" is measured; the gap is
"estimated recoverable", never "saved" — the caption says so verbatim, and the
recoverable dollar routes through the framing block (tokens for subscription).

Both /cost and /cost/cache share a single `_framing_block` helper (window-
independent plan mix, #177) so neither re-derives the suppression rules.

Tests: endpoint tests (httpx + InMemoryBackend) pin the reusable series shape,
the hit-rate/captured math, the recoverable passthrough, and subscription
framing; static-grep UI regressions assert the stacked + cache charts/helpers
and the honesty caption are present; test_ui_offline stays green; the extracted
app module passes `node --check`.

Closes #213
Closes #212

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(lens): add Wave 1 cost-chart review screenshots

Review aids for the #212/#213 PR — the stacked cost-by-model/agent chart and the
cache-savings time-series (captured vs estimated-recoverable). Kept under
docs/lens/wave1/; drop in review if binaries on main are undesired.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: drop committed Lens screenshots from the diff

Keep main binary-free — review screenshots belong in the PR description, not in
git history. The captures are preserved out-of-repo for review/docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
anilmurty added a commit that referenced this pull request Jun 23, 2026
…een (#224)

The differentiated Lens viz (#211, milestone #3): split the window's spend into
the four token components and overlay each optimize analyzer's attributed
recoverable waste — the cost-WASTE view a generic activity dashboard can't show
because it depends on our analyzers' attributed estimates.

New GET /api/v1/cost/components computes, server-side:
- the component cost split (input / output / cache-read / cache-write), priced
  per (provider, model) via the pricing table so it's exact, not apportioned
  from the aggregate cost_usd; and
- a registry-driven per-analyzer recoverable list — it iterates the typed
  downgrade slot plus every wave-2 finding carrying the #111 recoverable
  contract field, so a new analyzer appears automatically with no code change.
  Each entry keeps the analyzer's own caveat + estimate_basis verbatim and the
  component its savings act on ("call" = whole-call model swap / call
  elimination, for analyzers that can't be honestly pinned to one component).

The UI adds a ComponentWasteChart (vendored uPlot stacked bars, offline intact):
two columns — measured "Cost" stacked by component and "Recoverable (est.)"
stacked by analyzer. They are SEPARATE bars; recoverable is never subtracted
from cost and never called "saved" (Critical Rule 14) — the caption reads
"a heuristic estimate to review before acting, not a realized cost reduction".
A per-analyzer list under the chart surfaces each estimate behind the
"estimated recoverable" tag with its caveat. Every figure routes through the
framing block (fmtFramedSavings / fmtFramedDollar) so subscription/local users
see token-share, not raw dollars, and the bars themselves switch to token
volume. The endpoint fetch is best-effort — a failure never blanks Optimize.

Tests: endpoint tests (httpx + InMemoryBackend) pin the per-component pricing,
the registry-driven recoverable (reuse appears from the findings dict), the
downsize caveat verbatim, "saved" absent from the payload, and subscription
framing; static-grep UI regressions assert the chart/helpers, the registry-
driven build (no hard-coded analyzer list), the honesty caption + "saved"
absent from the surface, and the framing routing; test_ui_offline stays green
and the app module passes node --check.

Closes #211

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
anilmurty pushed a commit that referenced this pull request Jul 2, 2026
#4)

Claude Code's built-ins leave a real, documented gap: /compact is reactive,
lossy and single-session; /context shows current-session totals only. Neither
attributes WHAT is burning quota across sessions nor suggests a structural fix.
A whole DIY ecosystem (ccusage, codeburn, context-analyzer, session-recall, ...)
has sprung up to fill it — the strongest revealed-demand signal. Proof point:
anthropics/claude-code#24147, where a dev hand-parsed 30 days of JSONL to find
CLAUDE.md re-reads consumed 99.93% of their quota.

`tj context` runs a local diagnostic over Claude Code sessions and reports:

1. Per-turn context composition — what share of each turn went to RE-READING
   prior context (cache-read tokens: conversation history, CLAUDE.md, accrued
   tool output) vs. NET-NEW WORK (uncached input + output), with the re-read
   overhead named.
2. Recurring inclusions — the same file re-read across many sessions,
   frequency-counted, each with a concrete `@file` / CLAUDE.md structural fix
   (capture-gated on `[capture] tool_inputs`).
3. Compact candidates — sessions whose accumulated re-reading makes a
   mid-session /compact reclaim the most quota.

Framing is quota-native (the subscription majority): headline numbers render as
token-share / "% of cycle tokens" via core/framing.py — the single source of
truth for plan-tier-aware rendering — for Pro/Max users. Dollars are a SECONDARY
calibration signal for API users, never the headline. Output is a
screenshottable terminal card; `--json` for machine-readable output.

Honesty discipline (CLAUDE.md Rule 14): every figure is a measured token share
or a structural candidate flag, never a guaranteed saving; re-read tokens are
cache reads (billed at a reduced rate, not free) — real quota, stated as such.

Needs a direct DuckDB connection (reads the raw `attributes` column, which the
API shim doesn't expose) — fails gracefully with a `tj stop` hint when the
daemon holds the lock, mirroring `tj report --trim`.

Scoped OUT of v1 (named, not faked): MCP schema-injection attribution and
prompt-cache-miss attribution aren't derivable from current backfill data;
recurring-inclusion detection covers file Reads only. Per the #3 handoff,
content lands only on freshly-ingested spans after enabling `[capture]` — the
command surfaces that nudge rather than silently showing empty recurring data.

Covered by tests/unit/test_context_diagnostic.py over a synthetic multi-session
fixture: per-turn re-read-vs-work composition, cross-session recurring-inclusion
detection with structural fix, compact-candidate detection, the capture-off
nudge, and end-to-end CLI rendering of quota-share for a Max plan.

Co-Authored-By: Claude <noreply@anthropic.com>
anilmurty pushed a commit that referenced this pull request Jul 2, 2026
The Claude Code backfill ran one existence-check SELECT plus one INSERT per
span in `_insert_session_idempotent` — ~2 DuckDB round-trips per span, so a
large history (~120k spans) paid ~240k statements (~100s). #13 bounded only
the quickstart first-run path; the full `tj backfill claude-code` / daemon
path still paid the full per-span cost.

Replace the per-span loop with a bulk path that processes a whole session in
a BOUNDED number of statements regardless of span count:

- Partition new-vs-existing span_ids in ONE chunked `WHERE span_id IN (...)`
  query (`_existing_span_ids`) instead of N existence SELECTs.
- Bulk-insert the new spans in a single `executemany` (`_SPAN_INSERT_SQL` +
  `_span_insert_params`, kept in lock-step with `DuckDBBackend.insert_span`).
- On `--reingest`, batch-load the existing rows' attributes in ONE chunked
  query (`_load_attrs_bulk`), compute the per-key attribute merge in Python,
  then apply the updates in a single `executemany`.

The #10 idempotency + reingest contract is preserved exactly: new spans
insert; existing spans without `--reingest` are skipped untouched; existing
spans with `--reingest` get `sub_agent_id` updated and `attributes` per-key
merged (overlay `{**stored, **parsed}`, parsed wins, never wipes a stored
key). The no-`conn` fallback path is unchanged. Drops the now-unused
single-span `_load_attrs` helper.

Tests: all existing #3/#10/#13 backfill tests pass unchanged. Adds four #15
tests — bulk insert lands every new span; existing spans are skipped without
`--reingest`; `--reingest` still merges attributes (overlay, no wipe) +
updates sub_agent_id; and a counting-connection test asserting a 400-span
session inserts in a BOUNDED number of statements (well under N execute()
calls, via executemany) rather than ~2 per span.

Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit 6f94fe0)
anilmurty pushed a commit that referenced this pull request Jul 2, 2026
… flags (#3)

The Claude Code JSONL backfill parser recomputed cost from token/model
metadata but never extracted per-message content or tool-input from the
transcript — even though that data is present and core/transcript.py already
reads it. Because backfill bypasses IngestPipeline/strip_captured_content, the
[capture] toggles were a no-op on the CC path: flipping capture.prompts changed
nothing. This blocked the context-cost diagnostic (#4), which needs per-message
content + inclusion args to attribute tokens.

parse_claude_code_session now accepts a CaptureConfig and, gated per toggle,
populates the assistant LLM span with gen_ai.prompt.content (the triggering
human prompt) and gen_ai.completion.content (the agent narration), and each
tool span with gen_ai.tool.input (the raw args). The keys match GenAIAttributes
so downstream consumers and alert content-stripping treat backfilled content
identically to live content. ingest_claude_code reads config.capture and
forwards it; iter_claude_code_sessions threads it through.

Extraction is strictly opt-in: the None default and the all-False CaptureConfig
default leave every span's attributes byte-for-byte unchanged ({"source": ...}),
so a default backfill is unchanged and stays 100% local. Reuses _block_text from
core/transcript.py for the record-walking.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant